请将此答案视为对 Steve Greatrex 现在接受的答案的“扩展评论”:评论太长了,我想展示一些选项,添加一些“口味”。这根本不是对史蒂夫回答的“批评”,恕我直言,它击中了“靶心”。
假设:如果我之前阅读过这个问题,我会通过对这些要点的评论来查询 OP:
OP 没有指定要“显示”的表单是否以模态方式显示。
OP 没有指定是否每次显示表单时都重新创建它,或者是否应该创建并重新使用它的一个实例。
OP 写道“打开一个允许用户在其上选择选项的 winform ... snip ...“返回他选择的选项/值”:Steve 的代码并未准确显示属性如何暴露为Public 已设置,但我将假设 OP 可能意味着用户与显示的表单上的某些控件进行交互,并且他所指的“选项/值”是表单上控件的属性:比如最终用户在 TextBox 中键入一些文本,或者在 ListBox 中键入选定的索引,并将其 SelectionMode 设置为允许多选的两种选择之一。
-
OP 没有说明是否希望表单(如果重复使用)保留最终用户与表单上的控件的最后一次交互的结果,如上所述。
李>
-
OP 没有说明 UserControl 显示的 Form 是否将其 Parent 属性设置为其他有效容器:我假设他们的意思是“无父”显示 Form。
评论:
如果 OP 打算以模态方式显示表单:为了让史蒂夫的代码正常工作,必须将表单的“控制框”作为一个选项删除,并放置一个按钮在“DialogResult 属性设置为“OK”且“Click Event 关闭 Form”的表单上:如果不满足这些条件,Steve 代码中 ShowDialog 的结果将永远不会返回“OK”,并且属性值永远不会是放。注意:通过 'ControlBox 关闭表单将返回“取消”的 DialogResult。
重复使用显示的表单:如果我们假设表单可能会被重复使用,那么为什么不创建一次并根据需要“显示并关闭”呢?让我们考虑一下是否有充分的理由将创建的表单公开为 UserControl 的公共成员。
考虑以下替代想法:尝试提出与史蒂夫的解决方案尽可能“不同”的解决方案:只是为了展示、探索选项。
我们的“显示表单”将有一个 TextBox 和一个 ListBox 允许多选:我们的目标是公开 TextBox 中的 Text 和 ListBox 中当前选择的索引。
Form 有一个 ControlBox :不需要 Button 来关闭,如上所述。
Form 是否以模态方式显示都没有关系:在任何一种情况下都会以相同的方式设置属性。
要设置的公共属性将基于读取显示窗体上控件的当前状态。
表单被创建一次并公开为 Public :因此,“副作用”是当重新显示表单时,它将保留用户选择的先前结果等。当然还有其他方法可以让您在代码中轻松控制它,以使一个或所有控件再次“处女”。
在我们命名为“DataEntryForm”的“显示表单”中:
正如史蒂夫展示的那样,我们定义了要公开的公共属性;
public string TextEntered { get; set; }
public ListBox.SelectedIndexCollection LBSelection { get; set; }
在表单关闭事件中,我们根据控件的状态更新属性:
private void DataEntryForm_FormClosing(object sender, FormClosingEventArgs e)
{
TextEntered = textBox1.Text;
LBSelection = listBox1.SelectedIndices;
}
在 UserControl 我们创建一个类型为“DataEntryform”的公共属性(原因需要解释)
public DataEntryForm theDataEntryForm { get; set; }
我们在 UserControl 的 Load Event 中创建 DataEntryForm 的实例,并将其分配给 public Property
private void UserControl1_Load(object sender, EventArgs e)
{
theDataEntryForm = new DataEntryForm();
}
此时,我们将把它留给 OP(和您)的想象,以想象何时显示 DataEntryForm 的实例。但是我们当然想演示在 Form 关闭后如何访问属性:所以我们在 UserControl 上放置了一个 Button:
private void button2_Click(object sender, EventArgs e)
{
Console.WriteLine(theDataEntryForm.TextEntered);
Console.WriteLine(theDataEntryForm.LBSelection.ToString());
}
注意:我们没有对 ListBox 选择的索引进行任何“花哨”的分析:但我们可以写出它是否为空,或者选择了多少项等。
另外:我们没有处理如果 OP 想要在“显示的表单”关闭时采取一些行动的问题:这很简单:您只需订阅 UserControl 中 Form 的 FormClosed 事件,并在您的事件处理程序代码中执行您需要执行的操作。
最后我们来问为什么要创建一个类型为 'DataEntryForm 的公共属性:
好吧,只需考虑通过 UserControl 中的公共属性公开“显示的表单”:我们允许 UserControl 实例的潜在容器(可能是表单)也可以访问“显示形式” ...这可能很有价值,可以为我们节省一些重复的属性。
因此,如果 UserControl1 在 Form1 上,并且 Form1 想知道“显示的表单”上 TextBox 的 Text 值:可以像这样访问它:
this.userControl11.theDataEntryForm.TextEntered
编辑:我的一个朋友写信给我表达他的观点,即允许“更高级别”容器直接访问嵌入在 UserControl 中的“组件”是“违反”良好 OOD 实践并破坏封装:他发布我是一张移动违规罚单:) 所以,请记住他的警告。从他的角度来看,属性应该在 UserControl 中以不同的名称复制,并且只有那些 UserControls 属性才可用于 UserControl 容器。我的偏见是在这里将“UserContro/Form”视为一个“复合对象”,由于该表单仅供 UserForm 使用,因此有理由不复制 Properties /Edit
当然,由于我们都虔诚地这样做,我们已经忽略了检查所有可能为空的值。