【问题标题】:Is there a variant of Control.BeginInvoke which works before/after the handle is destroyed?是否有 Control.BeginInvoke 的变体在句柄被销毁之前/之后工作?
【发布时间】:2010-12-22 21:09:26
【问题描述】:

我有一个显示底层异步对象状态的控件。对象引发事件,这些事件到达表单,在那里它们基本上被排队并最终使用 BeginInvoke 调用。

在释放控件时出现问题。因为事情是异步发生的,这意味着在处理过程中总是有可能事件回调排队,我有时会收到一个 InvalidOperationException(在创建窗口句柄之前无法在控件上调用 Invoke 或 BeginInvoke。)。

这不是我想要的行为。即使控件已被释放,我也希望执行回调(即使这会导致回调中出现异常;这对我来说是一个更有用的异常!)。我想在每个回调中处理已释放的状态行为(如果已释放,通常只是跳过,但有时不会[例如,一个控件记录事件(可选到文件)并且我不想丢失日志数据!]。)。

有没有一种方法可以按我想要的方式工作?我可以自己写一个不脆的吗?

【问题讨论】:

    标签: .net winforms asynchronous controls begininvoke


    【解决方案1】:

    改用SynchronizationContext.Current。这有PostSend 成员,大致 映射到Control 上的BeginInvokeInvoke。只要 UI 线程相对于特定控件处于活动状态,这些操作就会继续起作用。

    SynchronizationContext 类型并非特定于 WinForms,利用它的解决方案可以移植到 WPF 等其他框架。

    例如。

    BeginInvoke 代码

    void OnButtonClicked() {
      DoBackgroundOperation(this); 
    }
    
    void DoBackgroundOperation(ISynchronizedInvoke invoke) {
      ThreadPool.QueueUserWorkItem(delegate { 
        ...
        delegate.BeginInovke(new MethodInvoker(this.BackgroundOperationComplete), null);
      });
    }
    

    同步上下文代码

    void OnButtonClicked() {
      DoBackgroundOperation(SynchronizationContext.Current);
    }
    
    void DoBackgroundOperation(SynchronizationContext context) {
      ThreadPool.QueueUserWorkItem(delegate {
        ...
        context.Post(delegate { this.BackgroundOperationComplete() }, null);
      });
    }
    

    【讨论】:

    • 你能举个使用例子吗?它是控件的成员还是全局事物?
    • 谢谢,这真的很有用。它可能也适用于许多其他场景。
    • 如果句柄可能不存在,我不太清楚如何获取控件并获取其同步上下文。
    猜你喜欢
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    • 2012-04-16
    相关资源
    最近更新 更多