【问题标题】:Closing a form during a constructor在构造函数期间关闭表单
【发布时间】:2010-06-18 07:39:34
【问题描述】:

是否可以在构造函数执行时关闭表单(或者只是在此阶段停止显示)?

我有以下代码:

public partial class MyForm : Form
{        
    public MyForm()
    {
        if (MyFunc())
        {
            this.Close();
        }
    }
}

在 Main() 中抛出 ObjectDisposedException,这里:

    static void Main()
    {            
        ...

        // Following line errors
        Application.Run(new MyForm());
    }

我试过这样检查 MyForm 的结果:

static void Main()
{            
    ...

    MyForm frm = new MyForm();
    if (frm != null)
    {
        // Following line errors
        Application.Run(frm);
    }
}

但这似乎没有帮助。谁能告诉我解决这个问题的方法吗?也许是一种检查表单以查看它是否仍然存在的方法?

【问题讨论】:

    标签: c# winforms constructor


    【解决方案1】:

    无法从表单的构造函数调用Close,因为它将在尚未创建的表单上调用Dispose。要在构建后关闭表单,请为 Load event 分配一个匿名事件处理程序,该处理程序会在您的表单首次显示之前关闭它:

    public partial class MyForm : Form
    {
        public MyForm()
        {
            if (ShouldClose())
            {
                Load += (s, e) => Close();
                return;
            }
    
            // ...
        }
    
        // ...
    }
    

    【讨论】:

    • +1,只需将 Shown 替换为 Load 就不会闪烁,您就有了胜利者
    • @Dialectus:谢谢。完成!
    • 这给了我这个错误:“在执行 CreateHandle() 时无法调用 Value Close()”
    • 太棒了!谢谢(:
    • 克里斯蒂安,这真是太棒了!谢谢!
    【解决方案2】:

    你唯一能做的就是在构造函数中设置一个标志来关闭它,然后在Shown事件中关闭它。当然,如果您这样做,那么首先移动代码以确定是否应该在此处关闭它是有意义的。

    【讨论】:

      【解决方案3】:

      以下效果很好:

      public partial class MyForm : Form
      {        
          public MyForm()
          {
              if (MyFunc())
              {
                  this.Shown += new EventHandler(MyForm_CloseOnStart);
              }
          }
      
          private void MyForm_CloseOnStart(object sender, EventArgs e)
          {
              this.Close();
          }
      }
      

      【讨论】:

        【解决方案4】:

        当您在表单上调用 Close() 时,它在内部处理表单并释放所有托管资源。当你这样做时:

        Application.Run(new MyForm());
        

        您可能会收到 ObjectDisposedException。您需要做的是通过属性设置表单的可见性:

        Application.Run(new MyForm() { Visible = false });
        

        只需确保在构造函数中删除对 Close() 的调用,甚至将属性分配也移到那里。

        【讨论】:

          【解决方案5】:

          您可以将 MyFunc 设为静态吗?然后执行以下操作:

          static void Main() 
          {             
              ... 
              if (MyForm.MyFunc())
              {
                  Application.Run(new MyForm()); 
              }
          } 
          

          这基本上可以让您同样控制是否要构建表单?

          【讨论】:

            【解决方案6】:

            我发现向“加载”事件添加处理程序会更好,因为这样对话框根本不会显示。使用“显示”事件,您可能会短暂地看到对话框打开然后关闭,这可能会令人困惑:

            public partial class MyForm : Form
            {        
                public MyForm()
                {
                    if (MyFunc())
                    {
                        this.Load += MyForm_CloseOnStart;
                    }
                }
            
                private void MyForm_CloseOnStart(object sender, EventArgs e)
                {
                    this.Close();
                }
            }
            

            【讨论】:

              【解决方案7】:

              我认为在构造函数中关闭表单是不明智的。如果您这样做,您的表单用户将不知道是否显示对话框。

              以下代码可以正常使用:

              // in the parent form:
              public void ShowMyForm()
              {
                  MyForm form = new MyForm();
                  form.propertyA = ...;
                  from.propertyB = ...;
                  DialogResult dlgResult = form.ShowDialog(this);
                  ProcessDialogResult(dlgResult);
              }
              

              如果你在构造函数中决定是否显示Form,则必须在构造后添加代码来决定是否调用ShowDialog以及是否处理对话框结果。

              此外,您确定更改属性不会影响表单是否显示?也是在未来的变化之后?

              在构建过程中,表单尚未显示/打开。所以恐怕Close() 没有达到你的预期。

              简洁的方法是在 Form_Load 的构造函数中执行您想要执行的检查。为表单加载添加事件处理程序并在事件处理程序中进行检查。使用属性 DialogResult 来指示您决定不显示该表单。

              private void FormMain_Load (object sender, EventArgs e)
              {
                  if (FormShouldNotLoad())
                  {
                      this.DialogResult = System.Windows.Forms.DialogResult.Abort;
                      Close();
                      // Warning, this does not work, see below, (but we're almost there!)
                  }
              }
              

              代码的用户可以检查对话框的结果:

              // in the parent form:
              public void ShowMyForm()
              {
                  MyForm form = new MyForm();
                  form.propertyA = ...;
                  from.propertyB = ...;
                  DialogResult dlgResult = form.ShowDialog(this);
                  switch (dlgResult)
                  {
                      case System.Windows.Forms.DialogResult.Abort:
                          ProcessFormNotLoaded();
                          break;
                      case System.Windows.Forms.DialogResult.OK:
                          ProcessFormOk();
                          break;
                      // etc.
                  }
              }
              

              但是,在表单加载的事件处理程序中调用 Close() 将不起作用,因为只有在加载完成后才能正确调用 Close()

              因此,不要调用Close(),而应该BeginInvoke Close() 函数,这样在加载完成后会调用Close 函数:

              private void FormMain_Load (object sender, EventArgs e)
              {
                  if (FormShouldNotLoad())
                  {
                      this.DialogResult = System.Windows.Forms.DialogResult.Abort;
                      // invoke the Close function after Load completed
                      this.BeginInvoke(new MethodInvoker( () => this.CancelLoading())
                  }
              }
              

              【讨论】:

              • 这应该是接受的答案,当前接受的答案会编译但会出现运行时错误。
              • 这也是我最喜欢的答案,因为有比取消构造函数更好的方法来做到这一点。在我的情况下,它是关于在 Program.cs 中初始化的主窗体,所以如果我不希望它加载,那么我根本不会在我的新对象上调用“Application.Run”。这比使用事件等来防止闪烁要容易得多。
              • 嗯,在 DialogResult 设置为 DialogResult.Abort 后,似乎没有调用 this.CancelLoading()。如果 DialogResult 赋值行被移除,则调用成功。
              【解决方案8】:

              Environment.Exit(...) 正在为我工​​作(没有窗口闪烁):

              public partial class MyForm : Form
              {        
                  public MyForm()
                  {
                      if (weShouldClose)
                      {
                          Environment.Exit(0);
                      }
                  }
              }
              

              【讨论】:

                【解决方案9】:

                如果您希望您的窗口永远不会被看到
                (没有闪烁的窗口会立即打开然后消失)

                public new void Show()
                {
                    if (MyFunc())
                        base.Show();
                    else
                        ; // dispose or whatever
                }
                

                虽然Show(...) 有 2 个重载,ShowDialog(...) 也有 2 个。
                不适用于通过Application.Run() 打开的主窗体。但无论如何,谁会这样做呢?除了还有一种方法可以不使用Application.Run() 打开主窗体。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-08-26
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-03-22
                  • 2022-01-19
                  相关资源
                  最近更新 更多