c# - 调用 `ObjectDisposedException` 时避免 `Invoke`

标签 c# .net winforms multithreading invoke

我有两种形式,一种是MainForm,第二种是DebugForm。 MainForm 有一个按钮,可以像这样设置和显示 DebugForm,并传递对已打开的 SerialPort 的引用:

private DebugForm DebugForm; //Field
private void menuToolsDebugger_Click(object sender, EventArgs e)
{
    if (DebugForm != null)
    {
        DebugForm.BringToFront();
        return;
    }

    DebugForm = new DebugForm(Connection);

    DebugForm.Closed += delegate
    {
        WindowState = FormWindowState.Normal;
        DebugForm = null;
    };

    DebugForm.Show();
}

在 DebugForm 中,我附加了一个方法来处理串口连接的 DataReceived 事件(在 DebugForm 的构造函数中):

public DebugForm(SerialPort connection)
{
    InitializeComponent();
    Connection = connection;
    Connection.DataReceived += Connection_DataReceived;
}

然后在 Connection_DataReceived 方法中,我更新了 DebugForm 中的一个 TextBox,它使用 Invoke 进行更新:

private void Connection_DataReceived(object sender, SerialDataReceivedEventArgs e)
{           
    _buffer = Connection.ReadExisting();
    Invoke(new EventHandler(AddReceivedPacketToTextBox));
}

但是我有一个问题。一旦我关闭 DebugForm,它就会在 Invoke(new EventHandler(AddReceivedPacketToTextBox)); 行上抛出 ObjectDisposedException

我该如何解决这个问题?欢迎任何提示/帮助!

更新

我发现如果我在按钮事件点击中删除事件,并在该按钮点击中关闭表单,一切都很好,我的调试表单毫无异常(exception)地关闭了......真奇怪!

private void button1_Click(object sender, EventArgs e)
{
    Connection.DataReceived -= Connection_DebugDataReceived;
    this.Close();
}

最佳答案

关闭表单会处理 Form 对象,但不能强制删除其他类对它的引用。当您为事件注册表单时,您基本上是在为事件源(在本例中为 SerialPort 实例)提供对表单对象的引用。

这意味着,即使您的表单已关闭,事件源(您的 SerialPort 对象)仍在向表单实例发送事件,并且处理这些事件的代码仍在运行。那么问题是,当此代码尝试更新已处置的表单(设置其标题、更新其控件、调用 Invoke 等)时,您将遇到此异常。

因此,您需要做的是确保在表单关闭时取消注册该事件。这就像检测到表单正在关闭并取消注册 Connection_DataReceived 事件处理程序一样简单。您可以轻松地通过覆盖 OnFormClosing 方法并取消注册其中的事件来检测表单是否正在关闭:

protected override OnFormClosing(FormClosingEventArgs args)
{
    Connection.DataReceived -= Connection_DataReceived;
}

我还建议将事件 registration 移动到 OnLoad 方法的重写,否则它可能会在表单完全构建之前接收事件,这可能会导致令人困惑的异常.

关于c# - 调用 `ObjectDisposedException` 时避免 `Invoke`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12956288/

相关文章:

winforms - 使用 powershell 安装时显示自定义消息

c# - 使用 XMLTextReader 读取节点值

c# - 在 c# .net 中运行线程

c# - DataGridView CheckBox 行返回 null,直到单击复选框

c# - 使用 RestSharp 发布带有虚线元素名称的 XML

javascript - 需要 dotnet 正则表达式将下划线 (_) 替换为 0%

vb.net - 柱形图 - 设置 X 轴的字符串标签

c# - 如何在任何打开的窗口中获取鼠标下的文本

c# - 将未知大小的结构数组从 c# 传递到 c++ dll 并返回

c# - 用户单击 MessageDialog 上的按钮时如何调用 FileSavePicker?