I'm going to sketch out
one way of achieving multiple secondary Form updates here, but, keep in mind there are many ways you could approach this, and, without really knowing the overall purpose and design of your Application, selecting the best/better way(s) may be just a guess.
A key criterion here for architecture is whether you want to implement a "switchboard" kind of architecture where your Main Form is the "switchboard" and the secondary Forms are analogous to "telephones:" in other words the Main Form is a "hub" where "messages" are received from the secondary Forms, and "messages" are sent to the secondary Forms.
In this model, the secondary Forms
do not act on each other directly: they can only
trigger actions that are carried out by code in the Main Form.
Another model would be hard-coding messaging between objects/Forms: in this model, Form1 (with the Button) would update the Labels on Form2, and Form3, directly.
The sketch I'll show here is of a "switchboard" type model. It uses Delegates of Type 'Action ('Action and 'Func arrived with .NET Framework 2.0) to pass "messages," rather than using the Event/EventHandler convention. 'Action and 'Func give to C# a powerful syntax for dealing with what in C/C++, or other languages, with passing references to executable code ("function pointers"): 'Action and 'Func can deal with any number of strongly Typed parameters (well, last time I looked, up to seventeen without breaking a sweat).
1. The Main Form:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private Form1 f1 = new Form1();
private Form2 f2 = new Form2();
private Form3 f3 = new Form3();
public int count = 0;
private void Form1_Load(object sender, EventArgs e)
{
f1.Show();
f1.SendMessage = HandleMessage;
f2.Show();
f3.Show();
}
private void HandleMessage(Form form, Control control)
{
switch (form.Name)
{
case "Form1":
switch (control.Name)
{
case "button1":
f2.MsgLabelUpdate("message #" + (++count).ToString());
f3.MsgLabelUpdate("message #" + count.ToString());
break;
}
break;
case "Form2":
switch (control.Name)
{
case "button1":
break;
case "label1":
break;
}
break;
case "Form3":
switch (control.Name)
{
case "button1":
break;
case "label1":
break;
}
break;
}
}
}
Key points to note here are:
a. we injected a reference to executable code ('HandleMessage) into the 'SendMessage Delegate of Type 'Action in the
instance of 'Form1.
b. When the Button on Form1 is clicked, it executes the code in the MainForm 'HandleMessage, passing references to the Form, and the Button.
c. When the 'HandleMessage code detects that the message came from Button1 on Form1, it then calls the executable method in Form2, and Form3, which is exposed through their public Delegates of Type 'Action.
d. There's a bunch of other possibilities that are "sketched in" in the 'HandleMessage code just to give you an idea that you could be handling
many types of messages from any secondary Form using 'HandleMessage as a general-purpose "transmitter."
2. Form1 ... the Form with the Button ...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Action<Form,Control> SendMessage;
private void button1_Click(object sender, EventArgs e)
{
SendMessage(this, button1);
}
}
Note, as mentioned, that a reference to the executable code in the Main Form's 'HandleMessage Event was injected into the instance of Form1 by the Main Form.
3. Form2:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
MsgLabelUpdate = invokeLabelUpdate;
}
public readonly Action<string> MsgLabelUpdate;
private void invokeLabelUpdate(string theText)
{
label1.Text = theText;
}
}
Note that here, and in Form3, we don't
inject anything into the instance of the Form. We simply create an indirect public reference to the private 'invokeLabelUpdate method that is exposed to Form1
4. Form3:
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
MsgLabelUpdate = invokeLabelUpdate;
}
public readonly Action<string> MsgLabelUpdate;
private void invokeLabelUpdate(string theText)
{
label1.Text = theText;
}
}
Good question to ask:
Is it really
necessary to go to all this trouble to create
indirect exposure of objects and methods ?
My answer would be that it is not
absolutely necessary, but that doing things in this way ... a way which I might call "implementing formal message-passing" ... helps keep our objects (Forms in this case) loosely-coupled, and that is consistent with OO programming ideas that suggest that "separation of concerns" and "encapsulation" is a good thing.
Using the techniques shown here (or others, like them) can ensure that there are minimal possible side-effects resulting from the exposure ... to "outside" objects ... of Forms, Classes, etc.