Communicate between two windows forms in C#
Form1 triggers Form2 to open. Form2 has overloaded constructor which takes calling form as argument and provides its reference to Form2 members. This solves the communication problem. For example I've exposed Label Property as public in Form1 which is modified in Form2.
With this approach you can do communication in different ways.
Download Link for Sample Project
//Your Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2(this);
frm.Show();
}
public string LabelText
{
get { return Lbl.Text; }
set { Lbl.Text = value; }
}
}
//Your Form2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
this.mainForm.LabelText = txtMessage.Text;
}
}
(source: ruchitsurati.net)
(source: ruchitsurati.net)
In the comments to the accepted answer, Neeraj Gulia writes:
This leads to tight coupling of the forms Form1 and Form2, I guess instead one should use custom events for such kind of scenarios.
The comment is exactly right. The accepted answer is not bad; for simple programs, and especially for people just learning programming and trying to get basic scenarios to work, it's a very useful example of how a pair of forms can interact.
However, it's true that the coupling that example causes can and should be avoided, and that in the particular example, an event would accomplish the same thing in a general-purpose, decoupled way.
Here's an example, using the accepted answer's code as the baseline:
Form1.cs:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.Button1Click += (sender, e) => Lbl.Text = ((Form2)sender).Message;
frm.Show();
}
}
The above code creates a new instance of Form2
, and then before showing it, adds an event handler to that form's Button1Click
event.
Note that the expression (sender, e) => Lbl.Text = ((Form2)sender).Message
is converted automatically by the compiler to a method that looks something similar to (but definitely not exactly like) this:
private void frm_Message(object sender, EventArgs e)
{
Lbl.Text = ((Form2)sender).Message;
}
There are actually lots of ways/syntaxes to implement and subscribe the event handler. For example, using an anonymous method as the above, you don't really need to cast the sender
parameter; instead you can just use the frm
local variable directly: (sender, e) => Lbl.Text = frm.Message
.
Going the other way, you don't need to use an anonymous method. You could in fact just declare a regular method just like the compiler-generated one I show above, and then subscribe that method to the event: frm.Button1Click += frm_Message;
(where you have of course used the name frm_Message
for the method, just as in my example above).
Regardless of how you do it, of course you will need for Form2
to actually implement that Button1Click
event. That's very simple…
Form2.cs:
public partial class Form2 : Form
{
public event EventHandler Button1Click;
public string Message { get { return txtMessage.Text; } }
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
In addition to the event, I've also declared a property Message
that exposes the Text
property (and only the Text
property, and only as read-only in fact) of the txtMessage
control. This allows the subscriber to the event to get the value and do whatever it needs to with it.
Note that all that the event does is to alert the subscriber that the button has in fact been clicked. It's up to the subscriber to decide how to interpret or react to that event (e.g. by retrieving the value of the Message
property and assigning it to something).
Alternatively, you could in fact deliver the text along with the event itself, by declaring a new EventArgs
sub-class and using that for the event instead:
public class MessageEventArgs : EventArgs
{
public string Message { get; private set; }
public MessageEventArgs(string message)
{
Message = message;
}
}
public partial class Form2 : Form
{
public event EventHandler<MessageEventArgs> Button1Click;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, new MessageEventArgs(txtMessage.Text));
}
}
}
Then the subscriber can just retrieve the message value directly from the event object:
frm.Button1Click += (sender, e) => Lbl.Text = e.Message;
The important thing note in all of the above variations is that at no point does the class Form2
need to know anything about Form1
. Having Form1
know about Form2
is unavoidable; after all, that's the object that will create a new Form2
instance and use it. But the relationship can be asymmetrical, with Form2
being usable by any object that needs the features it offers. By exposing the functionality as an event (and optionally with a property), it makes itself useful without limiting its usefulness to only the Form1
class.
The best in this case would be to have some OptionsService
class/interface that is accessible via IServiceProvider
.
Just add an event when something changes, and the rest of the app can respond to it.