在您的代码中,您将 UserControl 视为静态类对象,使用它的类型来访问字段和属性:
public partial class ucModule2 : UserControl
{
public static Form2 fr2 = new Form2();
// (...)
}
那么,在Form1:
ucModule2.fr2.TopMost = false;
// (...)
ucModule2 与 UserControl 类型的名称相同,因此您尝试使用 Type 来设置属于 的字段/属性该控件的实例。
如果您将ucModule2 的实例添加到表单,则设计器会将UC 的第一个实例重命名为ucModule21。
像往常一样,将索引值(1,如果它是该类型的第一个实例)添加到创建的类型的名称。
您需要使用该 UserControl(或任何其他控件)的 Instance 成员,而不是其 Type。
有关该主题的一些文档:
Inheritance (C# Programming Guide)
Members (C# Programming Guide)
类和结构都有代表它们的数据的成员和
行为。一个类的成员包括所有在类中声明的成员
类,以及所有成员(构造函数和终结器除外)
在其继承层次结构中的所有类中声明...
Static Classes and Static Class Members
创建一个只允许一个自身实例的非静态类
要创建,请参阅:
Implementing Singleton in C#。
在为类型分配名称时遵循标准命名约定也很重要。大多数开发人员假设类型名称使用 Pascal Case 约定,而此类型的实例将使用 Camel Case 约定命名,如下所示:
MyUserControl myUsrControl = new MyUserControl();
myUsrControl.Show();
您还可以在此处查看两者使用的不同标记颜色
在 Form1 中:
从Form1(其父窗体)调用UserControl 的SetForm() 方法。
之后,Form1 可以使用 UserControl 的 public FormInstance 属性。
public partial class Form1: Form
{
// If an Instance of the UC has been added in the Form's Designer,
// use that instance reference instead
UCModule2 ucModule2 = new UCModule2();
private void Form1_Load(object sender, EventArgs e)
{
ucModule2.Location = new Point(100, 100);
this.Controls.Add(ucModule2);
ucModule2.SetForm(typeof(Form2));
}
private void UsrCtrlDialog_Click(object sender, EventArgs e)
{
ucModule2?.FormInstance?.Close();
}
}
在 UCModule2 中(使用正确的大小写重命名类型):
如果表单实例已被父表单关闭/处置,请重新创建一个新实例并重置公共 FormInstance 属性。
可以判断Form的实例是否被销毁,测试:
FormInstance is null || FormInstance.IsDisposed
public partial class UCModule2: UserControl
{
public Form FormInstance { get; private set; }
public Form SetForm(Type formType)
{
if (this.FormInstance == null || this.FormInstance.IsDisposed) {
this.FormInstance = (Form)Activator.CreateInstance(formType);
}
return this.FormInstance;
}
private void simpleButton1_Click(object sender, EventArgs e)
{
if (this.FormInstance is null || this.FormInstance.IsDisposed) {
this.SetForm(FormInstance.GetType());
}
this.FormInstance?.Show();
}
}
处理运行时生成的不同表单类型的集合
如果在此 UserControl 处于活动状态时需要生成多个表单,我们可以将由 UC 的父表单确定的表单类型的每个新实例添加到列表中。然后在父窗体决定 和/或当 UserControl 本身被销毁时处理列表中的每个窗体实例:
父Form可以调用SetForm(Type formType)公共方法,设置生成的Form类型。然后调用 CloseAllForms() 公共方法在需要时将它们全部关闭。 UC 在其句柄被销毁时调用相同的方法,以删除现有的 Form 实例(如果需要)。
表单更改表单类型只需调用SetForm() 与另一种类型:
ucModule2.SetForm(typeof(Form2));
// (... and after...)
ucModule2.SetForm(typeof(Form3));
UC 的按钮将生成指定的新表单类型。
In Form1:
public partial class Form1: Form
{
// If an Instance of the UC has been added in the Form's Designer,
// use that instance reference instead
UCModule2 ucModule2 = new UCModule2();
private void Form1_Load(object sender, EventArgs e)
{
ucModule2.Location = new Point(100, 100);
this.Controls.Add(ucModule2);
ucModule2.SetForm(typeof(Form2));
}
private void UsrCtrlChangeType_Click(object sender, EventArgs e)
{
ucModule2.SetForm(typeof(Form3));
}
private void UsrCtrlDialog_Click(object sender, EventArgs e)
{
ucModule2.CloseAllForms();
}
}
In UCModule2:
public partial class UCModule2: UserControl
{
List<Form> formsCollection = null;
public UCModule2()
{
InitializeComponent();
formsCollection = new List<Form>();
}
private Type FormType { get; set; }
// Check whether the new type is different before setting the property,
// in case the FormType property has an explicit setter.
public void SetForm(Type formType)
{
if (this.FormType != formType) {
this.FormType = formType;
}
}
public void CloseAllForms()
{
if (formsCollection != null && formsCollection.Count > 0) {
for (int i = formsCollection.Count - 1; i >= 0 ; i--) {
formsCollection[i].Dispose();
}
}
}
protected override void OnHandleDestroyed(EventArgs e)
{
CloseAllForms();
base.OnHandleDestroyed(e);
}
private void btnShowForm_Click(object sender, EventArgs e)
{
if (FormType == null) return;
var instance = (Form)Activator.CreateInstance(FormType);
formsCollection.Add(instance);
instance.Show();
}