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 中显示用户输入的文本。记住此时Input
window是关闭的,相当于你的情况
所以我会利用 Delegates 来实现这个目标。 delegate
可让您在 windows 之间传输数据,这正是您想要的。
在我的 Main
中,我会声明一个 public
委托,其签名如下:
public delegate void DataTransfer(string data);
也就是说,这个 delegate
代表一个接受单个 string
参数的方法,并且具有 void
return 类型。思路是让secondaryInput
window'call'一个方法在Main
,那个方法接受一个string
参数。因此,如果我们有办法从 Input
调用驻留在 Main
中的方法,并传递一个 string
,那么我们就可以在 Input
window,传给Main
window。到目前为止和我在一起吗?
现在,如果我在 Main
中编写这样的方法,并让它从 Input
中调用,那应该可以实现我们的目标。此处,txtDisplay
是 Main
形式中的 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();
}
}
BtnOpen
是 Main
表单中的 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
并调用它。 '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 能够保存您要传递的所有数据并将其传递回主函数一次。
我有一个表单,其中填充了从主表单创建的一组用户控件。一旦按下按钮关闭弹出窗口,我需要能够从主窗体访问这个 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 中显示用户输入的文本。记住此时Input
window是关闭的,相当于你的情况
所以我会利用 Delegates 来实现这个目标。 delegate
可让您在 windows 之间传输数据,这正是您想要的。
在我的 Main
中,我会声明一个 public
委托,其签名如下:
public delegate void DataTransfer(string data);
也就是说,这个 delegate
代表一个接受单个 string
参数的方法,并且具有 void
return 类型。思路是让secondaryInput
window'call'一个方法在Main
,那个方法接受一个string
参数。因此,如果我们有办法从 Input
调用驻留在 Main
中的方法,并传递一个 string
,那么我们就可以在 Input
window,传给Main
window。到目前为止和我在一起吗?
现在,如果我在 Main
中编写这样的方法,并让它从 Input
中调用,那应该可以实现我们的目标。此处,txtDisplay
是 Main
形式中的 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();
}
}
BtnOpen
是 Main
表单中的 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
并调用它。 '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 能够保存您要传递的所有数据并将其传递回主函数一次。