C#从将要关闭的弹出表单中获取变量

时间:2018-06-19 21:53:13

标签: c# .net winforms user-controls

我有一个表单,其中填充了从主表单创建的userControls数组。按下按钮后,一旦弹出窗口关闭,我需要能够从主窗体访问此userControls数组。如果我填写表单,然后在不关闭弹出窗口的情况下按主表单上的按钮,则会显示这些值。但是,如果我关闭弹出窗口,则不存在这些值。我的主要形式是静态的,因此我可以将其变量用于其他形式。

弹出代码:

 public ScanChannel[] controls;
    public ScanListSetup()
    {
        InitializeComponent();
        int numChans = Convert.ToInt32(Form1.Self.numChannels.Text);
        controls = new ScanChannel[numChans];

        // Create the UserControls
        for(int i = 0; i < numChans; i++)
        {
            controls[i] = new ScanChannel();
        }

        // Place them
        for (int i = 0; i < numChans; i++)
        {
            controls[i].Location = new Point(13,(35+25*(i)));
            this.Controls.Add(controls[i]);
        }

        doneButton.Location = new Point(82, 35 + (25 * (numChans + 1)));
        this.Size =new Size(280, 110 + (25 * (numChans + 1)));
    }

    private void doneButton_Click(object sender, EventArgs e)
        {
            Form1.Self.setChannelsToScan(controls);
        }

我需要以主要形式访问controls数组。主要形式的代码如下:

private ScanChannel[] channelsToScan;


private void configureScanListButton_Click(object sender, EventArgs e)
    {

        var form = new ScanListSetup();
        form.Show(this);
        scanListConfigured = true;
        this.channelsToScan = new ScanChannel[Convert.ToInt32(numChannels.Text)];

    }

public void setChannelsToScan(ScanChannel[] arr)
    {
        for (int i = 0; i < arr.Length; i++)
        {
            this.channelsToScan[i] = arr[i];
        }
    }

 private void scanButton_Click(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Test: " + this.channelsToScan[0].getDeviceType());
        // THIS PRINTS AN EMPTY STRING
    }

因此,如果在弹出表单仍处于打开状态时单击scanButton,则Debug writeLine将输出正确的值。但是,如果我在弹出菜单上单击doneButton后关闭了该表单,则Debug writeLine输出Test:便没有其他内容。

任何对此的帮助将不胜感激。谢谢。

1 个答案:

答案 0 :(得分:1)

您的问题实质上可以归结为将数据从辅助窗口(“弹出”窗口)发送到创建它的主窗口。无论您使用的是Windows Control对象还是诸如string之类的简单数据类型都没有关系,因此,我将使用一个简单的示例来说明如何处理这种情况。

假设您有一个Main格式的表格,如下所示。它具有一个OPEN按钮和一个TextBox

enter image description here

单击OPEN时,它会打开以下辅助输入窗口(您的弹出窗口),如下所示:

enter image description here

现在的想法是这样。您单击OPEN并打开Input表单,然后让用户在此处的TextBox中输入一些文本。单击OK按钮后,它应关闭Input窗口,并在Main窗口中显示用户输入的文本。请记住,此时Input窗口已关闭,这与您的情况相同。

因此,我将利用Delegates来实现此目标。 delegate使您可以在所需的窗口之间传输数据。

在我的Main中,我将声明一个public代表,其签名如下:

public delegate void DataTransfer(string data);

也就是说,此delegate表示一个采用单个string参数并具有void返回类型的方法。想法是让辅助Input窗口在Main中“调用”一个方法,该方法接受一个string参数。因此,如果有一种方法可以从Main调用位于Input中的方法并传递string,那么我们可以在{{ 1}}窗口,并将其传递到Input窗口。到目前为止和我在一起?

现在,如果我在Main中编写这样的方法,并从Main中调用它,那应该可以实现我们的目标。在这里,InputtxtDisplay形式的TextBox

Main

要完成此操作,我将以如下所示的public void ReceiveInput(string data) { txtDisplay.Text = data; } 形式定义类型为delegate的{​​{1}},并向其中注册DataTransfer方法。您后面的Main表单代码应如下所示:

ReceiveInput()

Mainpublic delegate void DataTransfer(string data); public partial class MainForm : Form { public DataTransfer transferDelegate; InputForm inputForm = null; public MainForm() { InitializeComponent(); transferDelegate += new DataTransfer(ReceiveInput); } public void ReceiveInput(string data) { txtDisplay.Text = data; } private void BtnOpen_Click(object sender, EventArgs e) { inputForm = new InputForm(transferDelegate); inputForm.Show(); } } 表单中的BtnOpen按钮,当单击它时,它将委托传递给OPEN表单,然后将其打开。因此,因此,我们现在需要修改Main表单:

Input

在这里,我们修改构造函数,以使其采用类型Input的{​​{1}},并将其设置为相同类型的本地实例。然后,在public partial class InputForm : Form { DataTransfer transferDel; public InputForm(DataTransfer del) { InitializeComponent(); transferDel = del; } private void BtnOK_Click(object sender, EventArgs e) { string data = txtInput.Text; transferDel.Invoke(data); Close(); } } 表单上单击delegate,我们接受用户输入的文本,并将该文本传递给所说的DataTransfer并调用它。 “调用”与以BtnOK形式调用方法相同。此时,您可以Input delegate窗口,如上所示,您仍然可以从Main表单访问用户输入的Clsoe()数据。

您可以使用相同的方法,并且可以使用Input来代替字符串。但是,这不是来回传递一堆控件的最佳方法,因此理想情况下,您将从弹出窗口中的那些控件中提取所需的数据,然后仅传递所述数据,而不是整个控件。


编辑:OP发布了错误的代码之后。

好的,这是您的问题。 string类不是常规类,而是从Main派生的控制元素。否则为GUI元素。您不应该使用GUI元素来传递数据。因为,当您执行Controls时,它会尝试从testUserControl获取文本,但是UserControlcontrolArr[i].getText();控件 ,它不会此时存在 ,因为您关闭了窗口。请记住,您只执行一次textItem,然后 *您必须将所有数据发送回主窗口*

您应该做的就是,简单地定义一个类,以保存要传递给主数据库的所有数据。例如这样的东西:

textItem

现在,不传递TextBox数组,而是传递delegate.Invoke()数组。这样,在public class DataToPass { public string TextBoxText { get; set; } public string SomeOtherData { get; set; } // Other stuff you want... } 表单中,您不必执行以下操作:

testUserControl

相反,您只需执行以下操作即可:

DataToPass

其中Main现在是类型controlArr[i].getText(); 的数组。

简单地,传递从controlArr[i].TextBoxText; 派生的控件不是一个好主意。只需创建一个能够容纳您要传递的所有数据的类,然后将其一次传递回主要对象即可。