【问题标题】:C# Get variable from popup form that will be closedC#从将要关闭的弹出表单中获取变量
【发布时间】:2018-06-19 21:53:12
【问题描述】:

我有一个表单,其中填充了从主表单创建的 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,则调试 writeLine 会输出正确的值。但是,如果我在单击弹出表单上的 doneButton 后关闭表单,则 Debug writeLine 会输出 Test: 而没有其他内容。

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

【问题讨论】:

    标签: c# .net winforms user-controls


    【解决方案1】:

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

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

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

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

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

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

    public delegate void DataTransfer(string data);
    

    也就是说,这个delegate 表示一个接受单个string 参数的方法,并具有void 返回类型。这个想法是让辅助Input 窗口“调用”Main 中的一个方法,并且该方法接受一个string 参数。因此,如果我们有办法从Input 调用驻留在Main 中的方法,并传递string,那么我们可以在Input 窗口中获取用户输入文本,并传递它到Main 窗口。到目前为止和我在一起?

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

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

    为此,我将在Main 形式中定义一个DataTransfer 类型的delegate,如下所示,并向其注册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();
        }
    }
    

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

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


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

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

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

    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 派生的控件并不是一个好主意。只需创建一个能够保存您要传递的所有数据的类,然后将其传递回主类。

    【讨论】:

    • 感谢您的回复。不幸的是,尝试此操作后我仍然遇到同样的问题。如果我删除Close() 并保持弹出窗口打开,我的主窗体可以访问数据。如果我关闭弹出窗口,它是空白的。我检查并调用了ReceiveData 函数,但是就像弹出窗口消失了一样;由于缺乏更好的术语,在我的 main.js 中取消引用该变量。对不起,如果我没有很好地解释这个问题。感谢您的帮助。
    • 也许分享你的代码,你可以上传到github。因为这应该有效,所以在关闭弹出窗口之前调用该方法并将值传递给Main,此时弹出窗口是打开还是关闭都没有关系。
    • 很遗憾,我无法按照公司政策发布我的代码。您是否认为问题可能是因为 C# 中的数组是引用类型?因此,通过删除弹出表单,我正在删除被引用的数组。如果我只发送一个字符串而不是一个数组,它就可以正常工作。
    • 我根本无法调试我看不到的代码。如果您无法按照公司政策共享代码,人们通常会创建一个模拟代码示例,在不共享实际代码的情况下复制问题。
    • 一种可能性是,当您在 C# 中执行 some_array = another_array; 之类的操作时,它会创建一个引用。因此,当原始数据消失时,重复数据也会消失。如果您正在做类似的事情,请尝试some_array = another_array.ToArray();
    猜你喜欢
    • 2012-05-12
    • 1970-01-01
    • 1970-01-01
    • 2013-11-23
    • 2016-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多