I'm trying to write a simple application that opens two forms and displays a "newButton" on Form2 in two different places depending on the number of clicks of "button1" in Form1.
int ButtonClick1 = 0;
private void button1_Click(object sender, EventArgs e)
{
ButtonClick1;
Button newButton1 = new Button();
newButton1.Name = "NewButton1";
newButton1.Text = "1";
Form2 frm2 = new Form2();
switch (ButtonClick1)
{
case 1:
button1.BackColor = Color.Red;
frm2.flowLayoutPanel1.Controls.Add(newButton1);
frm2.Show();
break;
case 2:
button1.BackColor = Color.Green;
frm2.flowLayoutPanel1.Controls.Remove(newButton1);
frm2.flowLayoutPanel2.Controls.Add(newButton1);
frm2.Show();
break;
case 3:
button1.BackColor = Color.Gainsboro;
frm2.flowLayoutPanel2.Controls.Remove(newButton1);
frm2.Show();
ButtonClick1 = 0;
break;
}
}
Every time I click on "button1" it's creating a new instance of Form2 because of frm2.Show()
but only with that line, I can see that it's actually doing something.
I don't know how to change it so that it would just update Form2 without opening new instances.
CodePudding user response:
Here is my take on what you are trying to achieve:
Form 1:
public partial class testform1 : Form
{
testform2 form2;
int cnt = 0;
public testform1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
cnt;
if (form2 == null)
{
form2 = new testform2();
}
form2.Show();
Button btn = new Button()
{
Text = "1",
Name = "NewButton1",
};
form2.AddButton(btn, (Button)sender, ref cnt);
}
}
Form 2:
public partial class testform2 : Form
{
public testform2()
{
InitializeComponent();
}
public void AddButton(Button NewButton, Button ParentButton, ref int counter)
{
switch (counter)
{
case 1:
flowLayoutPanel1.Controls.Add(NewButton);
ParentButton.BackColor = Color.Green;
break;
case 2:
flowLayoutPanel1.Controls.Clear();
flowLayoutPanel2.Controls.Add(NewButton);
ParentButton.BackColor = Color.Red;
break;
case 3:
flowLayoutPanel2.Controls.Clear();
ParentButton.BackColor = Color.Gainsboro;
counter = 0;
break;
}
}
}
You can pass the counter as reference in the AddButton method to update the value once it reaches 3.
CodePudding user response:
You have identified two things that need to happen to achieve your desired outcome:
- Manage the visibility of Form 2
- Have Form 2 respond to property changes in Form 1.
To keep the clutter to a minimum, I'll provide a link where you can browse the example code. This answer will focus on how to achieve the outcome in the FlowLayoutPanel
controls in Form2
when the button is clicked in Form1
.
Property Change for ClickCount
One clean approach is to make a bindable ClickCount
property in Form1
and a Button
to increment it. Whenever that property changes, it fires a PropertyChanged
event:
public partial class Form1 : Form , INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int _ClickCount = 0;
public int ClickCount
{
get => _ClickCount;
set
{
// Detect changes and notify when that happens
if(_ClickCount != value)
{
_ClickCount = value == 3 ? 0 : value;
PropertyChanged?.Invoke(
this,
new ClickCountPropertyChangedEventArgs(
nameof(ClickCount),
ClickCount));
}
}
}
}
The constructor for Form2
will bind this event source to a PropertyChanged
handler:
public Form2(INotifyPropertyChanged binding)
{
InitializeComponent();
binding.PropertyChanged = Binding_PropertyChanged;
}
One really nice thing about doing it this way is that Form1
doesn't need to know anything about Form2
(like whether it does or doesn't have FlowLayoutPanel
controls or what Form2
might plan to do with the information) and also would be unaffected by future changes to those things.
Handling the ClickCount changed event
When the PropertyChanged
handler in Form2
detects that the count has changed, it calls a specialized handler:
private void onClickCountChanged(int count)
{
labelClickCount.Text = $"Click Count = {count}";
buttonShowOrHideA.Visible = count == 1;
buttonShowOrHideB.Visible = count == 2;
}
You're probably wondering what happened to the "add" and "remove" statements for the buttons? Well here's the thing: why not let FlowLayoutPanel
do its job of rearranging the layout when buttons are shown or hidden? This way, all you have to do is place the buttons in the designer and you can subscribe to their click events just one time instead of having to do that every time the button is added or removed. It takes less overhead and there are fewer things to go wrong. Here are the handlers for the Red and Green buttons:
private void buttonShowOrHideA_Click(object sender, System.EventArgs e) =>
MessageBox.Show("Red one clicked");
private void buttonShowOrHideB_Click(object sender, System.EventArgs e) =>
MessageBox.Show("Green one clicked");
Showing and hiding Form2
Being able to show and hide Form2
repeatedly and keep it out in front of Form1
means making sure the Form2 gets disposed properly (in the end) but not prematurely and I would encourage you to browse the full code for this. The main highlight is that when the ShowForm
checkbox is true for the first time, it will instantiate Form2
by passing in a reference to itself.
if (checkBoxShowForm2.Checked)
{
if (_form2 == null)
{
_form2 = new Form2(binding: this);
}
_form2.Location = new Point(Location.X Width 10, Location.Y);
// Passing 'this' ensures Form 2 will stay in front of Form 1
_form2.Show(this);
}
else _form2.Hide();