关闭在 UserControl 中打开的一个或多个表单

Close a Form or multiple Forms opened in a UserControl

我有一个带有用户控件 (ucModule2) 的主窗体 (Form1)。
ucModule2 包含一个按钮 (simpleButton1),可打开另一个表单 (Form2)。
Form1 上,我有一个应该关闭 Form2 的按钮 (UsrCtrlDialog)。

我有两种情况:

场景一: 我的 ucModule2.cs:

public partial class ucModule2 : UserControl
{
    public static Form2 fr2 = new Form2();
    private void simpleButton1_Click(object sender, EventArgs e)
    {
        //Form2 fr2 = new Form2();
        fr2.Show();
        fr2.TopMost = true;
        textModule2 = textBox_ucModule2.Text;
    }
 }

Form1 用于关闭 Form2 的按钮:

private void UsrCtrlDialog_Click(object sender, EventArgs e)
{
    // Form2 fr2 = new Form2();            
    ucModule2.fr2.TopMost = false;
    ucModule2.fr2.Close();
    ucModule2.fr2.Dispose();
}

在这种情况下,Form2 仅打开一次,并在 Form1 中的 UsrCtrlDialog 按钮关闭时关闭。但是如果我想再次打开 Form2,我会在 fr2.Show() 上得到:

System.ObjectDisposedException exception ('Cannot access a disposed object.'`

我知道当我想再次打开时 Form2,没有创建 Form2 类型的新对象。
在旧的 Form2 关闭后,我该怎么做才能打开新的 Form2?

场景二: 我的 ucModule2.cs:

public partial class ucModule2 : UserControl
{
    //public static Form2 fr2 = new Form2();
    private void simpleButton1_Click(object sender, EventArgs e)
    {
        Form2 fr2 = new Form2();
        fr2.Show();
        fr2.TopMost = true;
        textModule2 = textBox_ucModule2.Text;
    }
}

在这种情况下,我可以打开与单击 simpleButton1 一样多的 Form2 windows。比如我按了3次simpleButton1。我将有 3 Form2 windows。

当我按下 UsrCtrlDialog 按钮表单 Form1 时,如何关闭 3 Form2 windows?我怎样才能将 fr2 对象从 ucModule2.cs 获取到 Form1.cs

在您的代码中,您将 UserControl 视为静态 class 对象,使用它的类型来访问字段和属性:

public partial class ucModule2 : UserControl 
{ 
     public static Form2 fr2 = new Form2();
     // (...)
}

然后,在 Form1 中:

ucModule2.fr2.TopMost = false;
// (...)

ucModule2 与 UserControl Type 同名,因此您尝试使用 Type 来设置Fields/Properties 属于该控件的 实例

如果您将 ucModule2 的实例添加到表单,那么设计器会将 UC 的第一个实例重命名为 ucModule21
像往常一样,将索引值(1,如果它是该类型的第一个实例)添加到创建的类型的名称。

您需要使用该 UserControl(或任何其他控件)的实例成员,而不是其类型。

有关该主题的一些文档:

Inheritance (C# Programming Guide)
Members (C# Programming Guide)

Classes and structs have members that represent their data and behavior. A class's members include all the members declared in the class, along with all members (except constructors and finalizers) declared in all classes in its inheritance hierarchy...

Static Classes and Static Class Members

To create a non-static class that allows only one instance of itself to be created, see:
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(使用正确的大小写重命名类型):

如果Form实例已经被父Formclosed/disposed,重新创建一个新实例并重置publicFormInstance属性.
可以判断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();
    }
}

处理在 运行 时间

生成的不同表单类型的集合

如果在此用户控件处于活动状态时需要生成多个表单,我们可以将由 UC 的父表单确定的表单类型的每个新实例添加到列表中。然后当父表单 决定 执行时处理列表中的每个表单实例 and/or 当 UserControl 本身被销毁时:

Parent Form可以调用SetForm(Type formType)public方法,设置要生成的Form类型。然后在需要的时候调用CloseAllForms()public方法将它们全部关闭。 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();
    }