如何在C#中从子表单的子表单传递数据到父表单?

3
我是c#的新手。在我的Windows表单项目中有以下内容:
Form1包含一个按钮和DataGridView。
Form2包含一个按钮。
Form3包含一个按钮和3个文本框。

screenshot

如屏幕截图所示,在form1中,我点击buttonOpenForm2,form2弹出。然后在form2中,我点击buttonOpenForm3,form3弹出,其中有3个文本框和一个按钮。现在这3个表单都已打开。

我在textBox1、textBox2和textBox3中输入值,并在单击buttonAddRow(来自form3)时,希望这些值插入到Form1中的DataGridView中。

我的问题是: 如何从form3(子窗体的子窗体)向Form1(父窗体)添加一行,而不关闭form2和form3?我的意思是我想在form2和form3仍然打开的情况下传递数据。

请帮助我。谢谢

Form1:

public partial class Form1 : Form
{


    public Form1()
    {
        InitializeComponent();

    }

    private void buttonOpenForm2 _Click(object sender, EventArgs e)
    {
        Form2 frm2 = new Form2();
        frm2.Show();
    }

}

表单2:

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
    }

    private void buttonOpenForm3 _Click(object sender, EventArgs e)
    {
        Form3 frm3 = new Form3();
        frm3.Show();
    }
}

表格3:

 public partial class Form3 : Form
  {
    public Form3()
    {
        InitializeComponent();
    }

    private void buttonAddRow _Click(object sender, EventArgs e)
    {
        //What to write here to insert the 3 textboxes values into DataGridView?

    }
}

你可以使用自定义事件处理程序。请参阅如何:引发和消耗事件Winforms 用户控件自定义事件 - huMpty duMpty
3个回答

4

你不能期望得到完整的、可以直接复制粘贴的代码。我在记事本中快速编写了这个示例,以便让你了解事件在这种情况下如何最好地工作。我假设Form1直接打开Form3。下面的解决方案展示了如何使用事件。

你的任务是通过在中间添加另一个表单Form2来使其正常工作。你可以通过通过Form2传播相同的事件来实现。

Form3.cs

public partial class Form3 : Form
{
    public event EventHandler<AddRecordEventArgs> RecordAdded

    public Form3()
    {
        InitializeComponent();
    }

    private void buttonAddRow _Click(object sender, EventArgs e)
    {
        OnRecordAdded();
    }

    private void OnRecordAdded() {
        var handler = RecordAdded;
        if(RecordAdded != null) {
            RecordAdded.Invoke(this, new AddRecordEventArgs(txtQty.Text, txtDesc.Text, txtPrice.Text))
        }
    }
}

AddRecordEventArgs.cs

public class AddRecordEventArgs : EventArgs
{
    public AddRecordEventArgs(string qty, string desc, string price) {
        Quantity = qty;
        Description = desc;
        Price = price;
    }

    public int Quantity { get; private set; }
    public string Description { get; private set; }
    public decimal Price { get; private set; }
}

Form1.cs

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void buttonOpenForm3_Click(object sender, EventArgs e)
    {
        Form3 frm3 = new Form3();
        frm3.RecordAdded += Form3_RecordAdded;
        frm3.Show();
    }

    private void Form3_RecordAdded(object sender, AddRecordEventArgs e) {
        // Access e.Quantity, e.Description and e.Price
        // and add new row in grid using these values.
    }
}

非常感谢。我将不得不更多地了解关于事件的内容,因为这对我来说是一个新主题,一旦我完成,我将测试您的代码。谢谢你。 - naouf

1

1个解决方案

您可以使用模式,通过构造函数(Show方法之前的特殊setter)将数据发送到更远的位置,并通过公共getter在窗口关闭后获取它们。

public partial class Form2 : Form
{        
    Data Data1 {get; set;}
    //Instead of Data you can pass Form1 class as parametr. 
    //But this might lead to unreadable code, and using too mutch methods and fields that could be private, public
    public Form2(Data data)
    {
        InitializeComponent();
        Data1 = data;
    }

    private void buttonOpenForm3 _Click(object sender, EventArgs e)
    {
        //Repeat pattern
        Form3 frm3 = new Form3(Data1);
        frm3.Show();
    }    
}

如果你愿意,可以不必调用第三个窗口的构造函数。只需创建第三个窗口的实例并将其存储在第一个窗体中,然后通过调用传递数据的第一个实例来显示它。但是,在更大规模的情况下,这可能是不好的实践。

2解决方案

您可以使用单例模式。在第一个窗体的构造函数中创建第一个窗体的实例,并在第三个窗体中使用它。但是,您需要确保在内存中不会有多个此对象的实例,始终只有一个。


非常感谢。我需要更多地了解事件,因为这对我来说是一个新的主题,一旦我完成了阅读,我会测试您的代码。谢谢。 - naouf

1

您可以将所有者传递给方法Show()以创建新的表单。然后,您可以从Owner属性中获取所有者表单。

private void buttonOpenForm2 _Click(object sender, EventArgs e)
{
    Form2 frm2 = new Form2();
    frm2.Show(this);
}

所以你可以获得Form1:

(Form1)frm2.Owner

并调用Form1类的公共方法,并将您的新数据传递给该方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接