从其他线程触发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,Object state)
   at System.Threading.ThreadHelper.ThreadStart()

但是,从这个堆栈跟踪中我无法真正确定访问时放置了哪个对象?是我的按钮吗?还是TabPages对象?

此外,当前取消绑定的按钮在关闭时由表单处理。但是我的猜测是,这种情况发生得足够晚,以至于发生崩溃。 我是否在我的按钮类中缺少某种方法的替代(例如Dispose),以便在处理致命事件之前取消订阅硬件事件?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...