Communicate between two windows forms in C#

I have two forms, one is the main form and the other is an options form. So say for example that the user clicks on my menu on the main form: Tools -> Options, this would cause my options form to be shown.

My question is how can I send data from my options form back to my main form? I know I could use properties, but I have a lot of options and this seems like an tedious odd thing to do.

So what is the best way?


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;
    }
}

alt text
(source: ruchitsurati.net)

alt text
(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.