【问题标题】:Updating observable collection from background thread + WPF + silent update从后台线程更新 observable 集合 + WPF + 静默更新
【发布时间】:2014-07-16 06:44:06
【问题描述】:

我计划创建一个线程安全的可观察集合,在其中我在后台运行任务并在使用调度程序获得结果时更新 UI。

我从互联网上下载了一个 ThreadSafe。但我有一个小问题。我希望在 UI 上进行静默更新。由于用户已经在工作或选择绑定集合,我不想打扰用户选择的条目。换句话说,当有新邮件到达时,我想添加一个类似于 Microsoft Outlook 的条目。

这可能吗,有没有这样的例子。

谢谢

【问题讨论】:

  • 您的方法有缺陷...如果您的ObservableCollection 是数据绑定到 UI 控件,那么您将获得著名的 您无法从不同的线程更新 UI 属性 错误。通常,我们只是在后台线程中获取和准备数据,然后在 UI 线程上更新 UI 集合属性。
  • @Sheridan 问题是我不能等到生成所有数据并阻止用户界面。我希望用户同时处理列表,它会更新为新条目(每个时不时地)最后,不会干扰用户的选择。
  • 也许你没有理解我的评论?当我们在后台线程中获取或准备数据时,我们不会等待或阻塞 UI 线程。无论如何,继续这条道路,我期待在这里看到您的下一个相关问题。
  • @Sheridan 请给我一些时间,我会再做一些编码并上传一段示例代码,同时感谢您的回复!

标签: wpf multithreading observablecollection


【解决方案1】:

您可以从 ObservableCollection 派生类并覆盖它的 OnCollectionChanged 函数,并在需要时提升它的处理程序。以下是代码。

 public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
 {
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
    private bool suspendCollectionChangeNotification;

  protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {

                if (!this.suspendCollectionChangeNotification)
                {
                    NotifyCollectionChangedEventHandler eventHandler = CollectionChanged;
                    if (eventHandler != null)
                    {
                        Delegate[] delegates = eventHandler.GetInvocationList();

                        // Walk through invocation list
                        bool isEventInvoked = false;
                        foreach (NotifyCollectionChangedEventHandler handler in delegates)
                        {
                            isEventInvoked = false;
                            if (handler.Target is DispatcherObject)
                            {
                                DispatcherObject dispatcherObject = handler.Target as DispatcherObject;

                                // This check is to make sure if the call on a different thread than the dispatcher.
                                if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)
                                {
                                    // Invoke handler in the target dispatcher's thread
                                    // Intentionally called begin invoke because there is a problem with Dispatcher.Invoke that it hangs when
                                    // called simultaneously
                                    dispatcherObject.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, handler, this, e);
                                    isEventInvoked = true;
                                }
                            }

                            if (!isEventInvoked)
                            {
                                handler(this, e);
                            }
                        }
                    }
                }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 2013-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多