我有2种形式,一种是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,它就会在
ObjectDisposedException
行上抛出一个Invoke(new EventHandler(AddReceivedPacketToTextBox));
。我怎样才能解决这个问题?欢迎任何提示/帮助!
更新
我发现是否在按钮事件click中删除了事件,然后在该按钮单击中关闭了表单,一切都很好,并且debugform毫无异常(exception)地被关闭了……多么奇怪!
private void button1_Click(object sender, EventArgs e)
{
Connection.DataReceived -= Connection_DebugDataReceived;
this.Close();
}
最佳答案
关闭表单将处理Form对象,但不能强行删除其他类对此对象的引用。在为事件注册表单时,基本上是在对事件源(在这种情况下为SerialPort
实例)提供对表单对象的引用。
这意味着,即使您的表单已关闭,事件源(您的SerialPort
对象)仍将事件发送到表单实例,并且处理这些事件的代码仍在运行。然后的问题是,当此代码尝试更新已处置的表单(设置其标题,更新其控件,调用Invoke
和&c。)时,您将收到此异常。
因此,您需要做的是确保关闭表单后注销该事件。这就像检测到表单正在关闭并取消注册Connection_DataReceived
事件处理程序一样简单。通过覆盖OnFormClosing
方法并在那里注销事件,您可以方便地检测到表单正在关闭:
protected override OnFormClosing(FormClosingEventArgs args)
{
Connection.DataReceived -= Connection_DataReceived;
}
我还建议将事件注册移至
OnLoad
方法的替代项,否则它可能会在表单完全构建之前接收事件,这可能会导致令人困惑的异常。关于c# - 调用 `ObjectDisposedException`时避免 `Invoke`,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12956288/