【问题标题】:Winforms UI Thread Marshalling BusinessObject list being updated from background threadWinforms UI 线程编组 BusinessObject 列表正在从后台线程更新
【发布时间】:2009-07-08 11:55:50
【问题描述】:

首先,我知道有很多问题和解决方案可以纠正来自后台线程以外的线程的线程编组。我发现的所有问题和解决方案都集中在列表或业务对象本身引发事件的场景, Windows 窗体可以订阅并正确地将更新编组到主 UI 线程。

在我的例子中,业务对象列表正在由单独层中的后台线程更新。我希望这个列表绑定到主线程上的控件。我真的需要从业务对象列表中向 UI 公开事件,以便可以正确编组更新吗?我可以不悄悄地更新业务对象列表并将这些更新传播到 UI,而不必以某种方式向 UI 公开列表更改事件吗?

编辑:

我的问题本质上是这样的:更改的 INotifyProperty 在属性更改后被触发。绑定到实现此接口的对象的控件将尝试更新,如果导致事件触发的线程不是 UI 线程,我们就有问题了。所以我们需要通知 UI 线程我们要更新,以便更新可以以线程安全的方式处理,这意味着后台线程更新对象不能简单地进行它的业务,它必须请求权限才能更新对象或要求 UI 代表其对对象进行更改。这就是我所说的 UI 被拉入句柄对象更新的意思。

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    我在this old usenet post 上发布了一个选项(包括示例) - 查找ThreadedBindingList(不要惊慌 - 大部分代码都是设置示例;列表类非常小);它可能会有所帮助,但 IMO 你可能会更好地稍后再进行 UI 更新......

    (不要错过帖子下方的更新)

    【讨论】:

    • 那个 ThreadedBindingList 看起来很不错。我想我会试驾一下。
    • 谢谢 Marc 我去看看。
    • Marc 你是在建议我让 UI 来处理更新吗?请在下面查看我对 Yoopergeek 的评论。
    • 我说这是一个可能的选择。 YMMV。然而,它确实使这种类型的跨线程工作变得复杂......
    • Marc,我刚刚测试了你的线程绑定列表,效果很好,有一些错误处理,我想我可以使用它。谢谢。
    【解决方案2】:

    我的经验是,如果您将业务对象绑定到 UI,则对这些对象所做的任何更改都必须在 UI 线程上隐式执行,否则您将获得跨线程异常。

    当这些对象数据绑定到 UI 时,从非 UI 线程更改对象是个坏消息。

    看看,如果你的对象实现了绑定友好的模式(例如INotifyPropertyChanged)并且你将这些对象中的一个/多个绑定到 UI,并且你在幕后以某种方式更新你的对象这会导致这些绑定友好事件中的任何一个在 UI 上崩溃,您的“对象已更改”通知正在成为 UI 代码的方式,从而导致跨线程异常。

    更新:绕过引发违规事件的对象的一种方法是实现某种“STFU”对象级变量,当对对象进行更新时,该变量可以设置为 true来自非 UI 线程的状态。然后,在您的“OnRaiseMyEvent(...)”方法中,您可以检查 STFU 变量的状态 - 如果为 true,则 STFU,否则,引发事件。

    更新#2:啊,随着问题的更新,这是我在这种情况下所做的:将ISynchronizeInvoke 传递给您的业务对象的构造函数。然后,业务对象可以处理它是否需要将事件提升编组到 UI 线程:

    public class MyObject { 
       private ISynchronizeInvoke _Invoker;
    
       public MyObject(ISynchronizeInvoke invoker) { 
          _Invoker = invoker;
       }
    
       private void OnPropertyChanged(string propertyName) {
          PropertyChangedEventHandler handlers = this.PropertyChanged;
          if (handlers != null) { 
          if (_Invoker.InvokeRequired) { 
            _Invoker.Invoke(handlers, new PropertyChangedEventArgs(propertyName)); 
          } else { 
             handlers(new PropertyChangedEventArgs(propertyName);
          }
       }
    }
    

    【讨论】:

    • 我知道这正是问题所在!我正在实现那些绑定友好的接口。但是,如果我让 UI 处理我对业务对象所做的更新,我就破坏了封装。用户界面正在被拉入处理所有权利都没有业务知道的更新。
    • @Mule:“UI 正在被拉入处理所有权利都没有业务知道的更新。” : 嗯,但这正是你首先实现绑定接口的原因。 . . UI 的职责是监听这些事件。
    猜你喜欢
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    • 2012-12-04
    相关资源
    最近更新 更多