【问题标题】:Cannot access a disposed object?无法访问已处置的对象?
【发布时间】:2011-10-23 00:46:24
【问题描述】:

我有一个倒数计时器表单 - 在第一个表单上,用户将输入倒计时时间 - 警告时间、结束消息等。还有两个单选按钮(最大/最小),根据选择的情况,它们将打开一个新的 Max 或 Min 形式,时间将实际开始倒计时。它工作正常并且按我的预期倒计时。但是,如果我退出 Max 或 Min 表单并尝试以新的时间再次运行,则会收到错误消息。代码如下 - 注意 ShowDialog(this);是我尝试过的 - 它让我可以关闭并打开新表格,但它实际上并没有开始倒计时。 UpdateLabels 是更新标签的函数。

                bool Max = rbMax.Checked;
                if (Max == true)
                {
                    //_Max.ShowDialog(this);
                    _Max.Show();

                }
                else
                    //_Min.ShowDialog(this);
                    _Min.Show();

                UpdateLabels();
            }

我还尝试了以下我在网上阅读的可能解决方案,但它也没有奏效......

    private void Max_FormClosing(object sender, FormClosingEventArgs e)
    {
        this.Hide();
        this.Parent = null;
    }

谁能帮帮我 - 如果需要,我可以发布 UpdateLabels 函数。我对 UI C# 开发很陌生,所以任何帮助都会很棒。谢谢。

【问题讨论】:

  • Form.ShowDialogForm.Show 之间的一个显着区别是前者不会自动Dispose 您的表单,而后者会。这样做的原因是,如果您显示一个无模式的表单(即使用Form.Show),程序执行会返回到您的代码在表单关闭之前,并且您无法知道何时关闭表格在您的 Form 课程之外关闭。因此,由于您没有好地方可以拨打Dispose,Windows Forms 会在适当的时间(当表单关闭时)为您接手。

标签: c# .net winforms forms


【解决方案1】:

如果对象不可用,则创建新实例

if(frmRGB==nullptr || frmRGB.IsDisposed==true ) { frmRGB=新表格(); }

【讨论】:

    【解决方案2】:

    在按钮点击事件中创建对象 像这样

    private void btn_supplier_order_Click(object sender, EventArgs e)
            {
                form_supplier_order so = new form_supplier_order();
                so.Show();
            }
    

    【讨论】:

      【解决方案3】:

      解决方法很简单,例如在按钮点击事件中实例化被调用表单的对象

      private void buttonSetting_Click( object sender, EventArgs e )
          {
              ***_setting = new SettingWindow();***  //When I need to show the settings window
      
              _setting.Show();
          } 
      

      【讨论】:

      • 欢迎来到stackoverflow!但是请不要发布之前已经提到的解决方案。这只是问题的噪音。
      【解决方案4】:

      您可以做的是在调用 .Show 方法之前添加以下检查:

      if(_Max == null || _Max.IsDisposed)
          _Max = new MaxForm();       
      
      _Max.Show();
      

      对于 _Min 形式也是如此

      【讨论】:

      • 谢谢 - 这种设计 - 可能是更好的方法。
      • 这不可靠。如果多个线程正在访问表单(或者可能是事件),则无法保证在 if 语句之后表单仍然为空。至少,如果您希望它起作用,您需要在表单的每个访问权限周围放置一个锁。
      【解决方案5】:

      问题是,已关闭的表单不能再使用(重新打开)。这就是为什么您发布的代码试图停止关闭并且只隐藏您的窗口。但为此,必须将 Cancel-property 设置为 true:

      private void Max_FormClosing(object sender, FormClosingEventArgs e)    {        
         this.Hide();        
         this.Parent = null;    
         e.Cancel=true;
      }
      

      要在以这种方式关闭后显示表单,请使用 Show() 方法显示它。

      但是,这可能只是一种解决方法,您可以通过其他设计解决问题。 也许明智的做法是在每次需要时创建表单的新实例,而不是每次都尝试重新打开它。这还有一个优点,即表单仅在真正需要时才请求资源。

      【讨论】:

      • 我现在就试一试——我现在就让你看看结果如何。 - 谢谢盐酸
      • 效果很好 - 很棒。非常感谢 HCL。只是为了一些理解,你能简要解释一下这是做什么的吗?干杯
      • @CollyMcK:我已经扩展了我的答案。好吗?
      • 感谢您的额外解释,是的,做更多设计可能会更好,但这种解决方法现在会很酷。
      • 不,这样会阻止您关闭表单。
      【解决方案6】:

      每当表单关闭时,其所有资源都会被释放。这意味着您不能再访问该对象,因为它不再存在 - 它已被释放并从内存中删除。为防止这种情况,您可以取消关闭表单,并改为隐藏它(这对用户来说是透明的)。

      this.Hide();        
      e.Cancel=true;
      

      您的代码的更新版本如下:

      private void Max_FormClosing(object sender, FormClosingEventArgs e)
      {
          e.Cancel = true;
          this.Hide();
          this.Parent = null;
      }
      

      【讨论】:

        猜你喜欢
        • 2011-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        相关资源
        最近更新 更多