在C#中的两个窗体之间进行通信

Bob*_*lan 38 c# properties winforms

我有两种形式,一种是主要形式,另一种是选项形式.例如,假设用户点击主窗体上的菜单:Tools -> Options这将导致我的选项表单显示.

我的问题是如何将我的选项表单中的数据发送回我的主表单?我知道我可以使用属性,但我有很多选择,这似乎是一件单调乏味的事情.

那么最好的方法是什么?

thi*_*eek 57

Form1触发Form2打开.Form2重载了构造函数,它将调用form作为参数,并提供对Form2成员的引用.这解决了通信问题.例如,我在Form1中将Label Property公开为public,并在Form2中进行了修改.

通过这种方法,您可以以不同的方式进行通信.

下载示例项目的链接

// 你的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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

// 你的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

替代文字http://demo.ruchitsurati.net/files/frm1.png

alt text http://demo.ruchitsurati.net/files/frm2.png

  • 这导致Form1和Form2形式的紧密耦合,我想相反应该为这种场景使用自定义事件. (5认同)

Pet*_*iho 15

在接受回答的评论中,Neeraj Gulia写道:

这导致Form1和Form2形式的紧密耦合,我想相反应该为这种场景使用自定义事件.

评论是完全正确的.接受的答案并不错; 对于简单的程序,特别是对于那些只是学习编程并试图让基本场景工作的人来说,它是一对表单如何交互的一个非常有用的例子.

但是,确实可以并且应该避免示例导致的耦合,并且在特定示例中,事件将以通用的,解耦的方式完成相同的事情.

这是一个例子,使用接受的答案代码作为基线:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码创建了一个新实例Form2,然后在显示它之前,为该表单的Button1Click事件添加了一个事件处理程序.

请注意,(sender, e) => Lbl.Text = ((Form2)sender).Message编译器会自动将表达式转换为类似于(但绝对不完全相同)的方法:

private void frm_Message(object sender, EventArgs e)
{
    Lbl.Text = ((Form2)sender).Message;
}
Run Code Online (Sandbox Code Playgroud)

实际上有很多方法/语法可以实现和订阅事件处理程序.例如,使用如上所述的匿名方法,您实际上不需要转换sender参数; 相反,你可以直接使用frm局部变量:(sender, e) => Lbl.Text = frm.Message.

另一方面,您不需要使用匿名方法.实际上,您可以像我上面显示的编译器生成的那样声明一个常规方法,然后将该方法订阅到事件:( frm.Button1Click += frm_Message;当然,您使用frm_Message该方法的名称,就像上面的示例中一样).

无论你如何做,当然你需要Form2实际实现该Button1Click事件.那很简单......

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

除了事件之外,我还声明了一个属性Message,该Text属性公开控件的属性(并且显示Text属性,并且仅作为只读)txtMessage.这允许事件的订阅者获得值并且用它做任何需要的事情.

请注意,事件的所有作用是提醒订户该按钮实际上已被点击.由订户决定如何解释或响应该事件(例如,通过检索Message属性的值并将其分配给某个东西).

或者,您实际上可以通过声明一个新的EventArgs子类并将其用于事件来传递文本以及事件本身:

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后订阅者可以直接从事件对象中检索消息值:

frm.Button1Click += (sender, e) => Lbl.Text = e.Message;
Run Code Online (Sandbox Code Playgroud)


所有上述变化中重要的一点是,课程在任何时候都不Form2需要知道任何事情Form1.有Form1知道Form2是不可避免的; 毕竟,这是将创建一个新Form2实例并使用它的对象.但是这种关系可以是不对称的,任何需要它提供的功能的对象Form2都可以使用它.通过将功能公开为事件(并且可选地具有属性),它使其自身有用而不仅限于其对类的有用性.Form1


lep*_*pie 6

在这种情况下最好的是有一些OptionsService可通过访问的类/接口IServiceProvider.

只需在更改内容时添加事件,应用程序的其余部分就可以对其进行响应.