C# 从将要关闭的弹出窗体中获取变量

C# Get variable from popup form that will be closed

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

弹出代码:

 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: 没有任何其他内容。

如有任何帮助,我们将不胜感激。谢谢。

您的问题本质上归结为将数据从辅助 window(您的 'pop-up' window)发送到创建数据的主要 window。不管你是在使用 Windows Control 对象还是像 string 这样的简单数据类型,所以我将使用一个简单的例子来说明如何处理这样的情况。

假设您有一个如下所示的 Main 表单。它有一个 OPEN 按钮和一个 TextBox.

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

现在的思路是这样的。您单击 OPEN 并打开 Input 表单,让用户在 TextBox 中输入一些文本。单击 OK 按钮后,它应该关闭 Input window,并在 Main window 中显示用户输入的文本。记住此时Inputwindow是关闭的,相当于你的情况

所以我会利用 Delegates 来实现这个目标。 delegate 可让您在 windows 之间传输数据,这正是您想要的。

在我的 Main 中,我会声明一个 public 委托,其签名如下:

public delegate void DataTransfer(string data);

也就是说,这个 delegate 代表一个接受单个 string 参数的方法,并且具有 void return 类型。思路是让secondaryInputwindow'call'一个方法在Main,那个方法接受一个string参数。因此,如果我们有办法从 Input 调用驻留在 Main 中的方法,并传递一个 string,那么我们就可以在 Inputwindow,传给Mainwindow。到目前为止和我在一起吗?

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

public void ReceiveInput(string data)
{
    txtDisplay.Text = data;
}

为了实现这一点,我将在下面的 Main 表单中定义类型为 DataTransferdelegate,并向其注册 ReceiveInput() 方法。您的 Main 后面的表单代码应如下所示:

public 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();
    }
}

BtnOpenMain 表单中的 OPEN 按钮,单击它时,它会将委托传递给 Input 表单,然后打开它。因此,相应地,我们现在需要修改我们的 Input 形式:

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

在这里,我们修改构造函数,使其接收类型为 DataTransferdelegate,并将其设置为相同类型的本地实例。然后,在 Input 表单上单击 BtnOK 时,我们接收用户输入的文本,并将该文本传递给所述 delegate 并调用它。 'Invoking'与调用Main形式的方法是一样的。此时,您可以 Clsoe() Input window 如上所示,您仍然可以访问 string 来自 Main 的用户输入数据形式。

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


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

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

你应该做的是,简单地定义一个 class 来保存你想要传递给你的主程序的所有数据。例如这样的事情:

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;

其中 controlArr 现在是 DataToPass.

类型的数组

简单地说,传递从 UserControl 派生的控件不是一个好主意。只需创建一个 class 能够保存您要传递的所有数据并将其传递回主函数一次。