c# - 从不同线程触发 UI 事件时的 ObjectDisposedException
问题描述
目前我有一个项目,其中包括一些 WinForms 绑定,以允许不仅使用鼠标操作界面,还可以通过外部硬件设备操作界面。
外部设备通过 DLL 连接,该 DLL 允许订阅硬件按钮推送事件,这些事件是从单独的线程发送的。
这是我为按钮制作的类的样子(省略细节):
public class PanelBoundButton : Button, IPanelBoundControl
{
/// <summary>
/// Gets or sets what hardware button the control is bound to.
/// </summary>
[Description("Panel button to bind"), Category("Hardware Interface")]
public HardwareButtonFlags Binding
{
get;
set;
}
// For debouncing
private DateTime pressTime = DateTime.MinValue;
private const int DEBOUNCE_MS = 100;
public void Bind()
{
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) return;
ButtonReader.ButtonsChanged += new EventHandler<HardwareButtonEvent>(HardwareHandleButtonChange);
}
public void Unbind()
{
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) return;
ButtonReader.ButtonsChanged -= HardwareHandleButtonChange;
}
// External hardware button event handler
void HardwareHandleButtonChange(object sender, HardwareButtonEvent e)
{
if (this.Binding != 0 && e.Released.HasFlag(this.Binding) && this.Enabled)
{
if(DateTime.Now.Subtract(pressTime).TotalMilliseconds < DEBOUNCE_MS)
{
Logger.Log("Button event seems like noise, ignoring for debouncing");
return;
}
pressTime = DateTime.Now;
Action clk = delegate()
{
this.PerformClick();
};
if (this.InvokeRequired)
this.Invoke(clk);
else clk();
}
}
}
但是,有时在操作按钮时,尤其是关闭表单的按钮时,用户会因以下堆栈跟踪而崩溃。最初我认为这可能是因为按钮按下被识别两次,因此上面代码的去抖动部分,但它没有帮助(并且去抖动行也从未被记录)。
Cannot access a disposed object.
Object name: 'AppOperationSelectorTabPages'.
Happened in object: System.Windows.Forms
Happened in method: System.Object MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean)
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at projectname.GUI.PanelBoundButton.HardwareHandleButtonChange(Object sender, HardwareButtonEvent e)
at System.EventHandler`1.Invoke(Object sender, TEventArgs e)
at projectIoLib.FrontPanel.ButtonReader.OnButtonEvent(Object sender, HardwareButtonEvent e)
at projectIoLib.FrontPanel.ButtonEventEmitter._ButtonCheckingThread()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
但是,从这个堆栈跟踪中,我无法真正确定在访问时处理了哪个对象?是我的按钮吗?还是那个 TabPages 对象?
此外,当前取消绑定按钮由窗体关闭时处理。然而,我的猜测是,这发生得太晚了,以至于崩溃发生了。我是否错过了Dispose
按钮类中某些方法(如)的覆盖,以便在处理它们变得致命之前取消订阅硬件事件?
解决方案
推荐阅读
- python - argparse 采用 int & string?
- terraform - 如何使 terraform 跳过破坏资源?
- c# - 如何处理异步方法抛出的混乱异常?
- rstudio - 安装 RSQLite 时如何修复“找不到‘blob’包”?
- git - Git合并所有剩余未合并路径的传入更改
- hive - Ambari集群重启报错:Timeline Service V2.0 Reader没有重启
- c++ - 从拉伸多边形生成 3D 网格
- vue.js - Vuejs 有效负载在突变中未定义。'无法设置未定义的属性'
- r - 使用 tidy_eval/rlang 上下文将函数作为参数传递
- python - 如何制作seaborn和bokeh plot的发布级别?