繁体   English   中英

如何多次打开 WinForm?

[英]How can I open a WinForm multiple times?

我尝试使用主窗体上的按钮打开第二个窗体,但是当我关闭第二个 window 时,我无法再次打开它。

我在主窗体中添加了以下代码:

settings_window secondForm = new settings_window();
private void settings_button_Click(object sender, EventArgs e)
{
    secondForm.Show();
}

但是,当我第二次尝试打开名为 settings_window 的第二个窗体时,出现以下错误:System.ObjectDisposedException。

我找到了以下代码来解决这个问题,但我不知道该把它放在哪里:

private void settings_window_FormClosing(object sender, FormClosingEventArgs e)
{
    this.Hide();
    e.Cancel = true;    // Do not close the form.
}

我认为每次要打开表单时都需要创建一个新的表单实例。 每次单击该按钮时,它都会创建一个新的 settings_window 表单实例。

private void settings_button_Click(object sender, EventArgs e)
{
    // Create a new instance of the form
    settings_window secondForm = new settings_window();
    secondForm.Show();
}

您可以避免存储 Forms 的引用,并使用一个简单的通用方法,当它的一个实例已经存在时显示一个表单,或者在之前没有创建一个实例时创建一个新的(并显示它):

private void ShowForm<T>() where T : Form, new()
{
    T? f = Application.OpenForms.OfType<T>().SingleOrDefault();
    if (f is null) {
        f = new T();
        f.FormClosing += F_FormClosing;
    }
        
    f.Show();
    BeginInvoke(new Action(()=> f.WindowState = FormWindowState.Normal));

    void F_FormClosing(object? sender, FormClosingEventArgs e)
    {
        e.Cancel = true;
        (sender as Form)?.Hide();
    }
}

当你需要它时,调用ShowForm<SomeFormClass>() ,例如,

ShowForm<settings_window>()

笔记:

  • 此代码使用本地方法订阅FormClosing事件。
    您可以使用标准方法,以防此语法不可用。
  • BeginInvoke()用于推迟FormWindowState.Normal分配。 这仅在最小化窗体的情况下使用,然后右键单击任务栏中的它的图标,然后从菜单中 select Close Windows 如果不推迟此分配,最小化的表单将不会再次出现。
  • 当起始表格关闭时,所有其他 Forms 也关闭
  • 此代码假设已启用nullable (例如,请参阅object? sender )。 如果 nullable 被禁用或者您的目标是 .NET Framework,请将其删除(例如,更改object sender

secondForm 是主窗体secondForm的私有字段吗? 它应该工作。

替代解决方案是将其显示为模态 - ShowDialog()

此外,如果您想在第二个表单中保存一些数据,只需使用构造函数中的一些数据初始化,然后保存到第一个/父表单。

您的代码显示了一个您已命名为settings_window的 class,这给了我们有关其预期用途的提示。 通常,对于行为“类似于”设置 window 的表单,您可以使用同一实例多次调用,您可以使用此模式声明成员变量:

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
        // Provide some means, like a menu or button, to show 'secondForm'
        settingsMenu.Click += onClickSettingsMenu;
        // Dispose the settings_form when the MainForm does.
        Disposed += (sender, e) => secondForm.Dispose();
    }
    // By instantiating it here, its public default or persisted 
    // properties are immediately available, for example even 
    // while the main form constructs and loads the initial view.
    settings_window secondForm = new settings_window();

    private void onClickSettingsMenu(object? sender, EventArgs e)
    {
        if(DialogResult.OK.Equals(secondForm.ShowDialog()))
        {
            // Apply actions using the properties of secondForm
        }
    }
}

这适用于您想要的任何形式:

  • 重复显示和隐藏表单(例如,用户可以多次更改选项的“设置”表单)。
  • 从一开始就检索表单的默认或持久属性,即使它从未显示过
  • 在应用程序运行时的任何给定时刻使用表单的任何公共属性(例如GameLevelSortType等),即使表单当前不可见。
  • 模态显示窗体意味着“除了模态窗体上的对象外,不会发生任何输入(键盘或鼠标单击)”。

它起作用的原因是调用ShowDialog (与调用Show不同)有意处理 window 句柄,这是为了支持这种情况。 然后,应用程序负责在应用程序关闭时处理资源。

Microsoft 的ShowDialog文档解释了它是如何工作的。

与非模态 forms 不同,当用户单击对话框的关闭窗体按钮或设置 DialogResult 属性的值时,.NET 框架不会调用 Close 方法。 相反,窗体是隐藏的,无需创建对话框的新实例即可再次显示。 因为显示为对话框的窗体是隐藏的而不是关闭的,所以当您的应用程序不再需要该窗体时,您必须调用该窗体的 Dispose 方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM