在主题列表框中更新的ObservableCollection [英] Update ObservableCollection in list box in thread

查看:397
本文介绍了在主题列表框中更新的ObservableCollection的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

海兰,

我有被绑定列表框观察的集合。我想补充记录到观察的集合。我总是立即添加消息观测Collecten。但是,当循环结束列表中只得到更新,但我想更新,当我在加入一个项目的循环。这就是为什么我使用一个线程,但我有几个问题。

I have a Observable Collection which is bind with a list box. I add logs to the Observable Collection. I always add the message immediately to the Observable Collecten. But the list gets only updated when the loop is finished but I want to Update it when I add one item in the for loop. This is why I use a Thread but I have a few problems.

我有一个线程安全的ObservableCollection:

I have a thread safe ObservableCollection:

class ThreadSafeObservableCollection<T> : ObservableCollection<T>
{
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler collectionChanged = this.CollectionChanged;
        if (collectionChanged != null)
            foreach (NotifyCollectionChangedEventHandler handler in collectionChanged.GetInvocationList())
            {
                DispatcherObject dispatcherObject = handler.Target as DispatcherObject;
                if (dispatcherObject != null)
                {
                    Dispatcher dispatcher = dispatcherObject.Dispatcher;
                    if (dispatcher != null && !dispatcher.CheckAccess())
                    {
                        dispatcher.BeginInvoke(
                            (Action)(() => handler.Invoke(this,
                                new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
                            DispatcherPriority.DataBind);
                        continue;
                    }
                }
                handler.Invoke(this, e);
            }
    }
}

这是我的测试类:

public partial class MainWindow : Window
{
    ThreadSafeObservableCollection<Animal> list = new ThreadSafeObservableCollection<Animal>();
    public MainWindow()
    {
        InitializeComponent();
        list.Add(new Animal() { Name = "test1" });
        list.Add(new Animal() { Name = "test2" });
        this.DataContext = list;
    }

    private void dsofsdkfd(object sender, RoutedEventArgs e)
    {
        //Version 1
        Task.Factory.StartNew(() => test());

        //Version2
        /*
        var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
        var token = Task.Factory.CancellationToken;

        Task.Factory.StartNew(() => test(), token, TaskCreationOptions.None, uiScheduler);
        */
    }

    public void test()
    {
        for (int i = 0; i < 10000; i++)
        {
            list.Add(new Animal() { Name = "test" + i });
            System.Threading.Thread.Sleep(1);
        }
    }
}

看到私人无效dsofsdkfd(对象发件人,RoutedEventArgs E)功能评论版本1 。 在它工作的起步阶段,所以名单更新,每次我添加一个项目。经过几个项目我得到一个异常:

See the private void dsofsdkfd(object sender, RoutedEventArgs e) function to the comment Version1. In the beginning it works so the list updates everytime I add a item. After a few entries I get an exception:

为开发信息(使用文字可视化阅读   此):\ r \ n此异常被抛出,因为发电机控制   System.Windows.Controls.ListBox Items.Count:1089名为记录仪   已收到序列CollectionChanged事件,不同意   Items集合的当前状态。下列   被检测到的差异:\ r \ N中所累加计数994是不同的   从实际计数1089. [累计计数(计数,最后复位+

"Information for developers (use Text Visualizer to read this):\r\nThis exception was thrown because the generator for control 'System.Windows.Controls.ListBox Items.Count:1089' with name 'Logger' has received sequence of CollectionChanged events that do not agree with the current state of the Items collection. The following differences were detected:\r\n Accumulated count 994 is different from actual count 1089. [Accumulated count is (Count at last Reset +

System.Windows.Controls.ItemContainerGenerator \ r \ñ
  System.Windows.Controls.ItemCollection \ r \ñ
  System.Windows.Data.ListCollectionView \ r \ N *
  WpfApplication1.ThreadSafeObservableCollection`1 [WpfApplication1.Animal,   WpfApplication1,版本= 1.0.0.0,文化=中立,   公钥=空] \ r \ N(带星号的来源被认为是更   可能是问题的原因。)\ r \ñ\ r \ n此最常见的原因   是(一)改变了收集或计数不养   相应的事件,和(b)引发一个事件有一个不正确的索引   或项目参数。\ r \ñ\ r \ n此异常的堆栈跟踪介绍   检测到的不一致,他们也不怎么发生的。为了得到一个   更及时的异常,设置附加属性   对发电机'presentationTraceSources.TraceLevel'珍惜'高'   并重新运行方案。这样做的一种方式是运行一个命令   类似以下内容:\ñ
  System.Diagnostics程序。presentationTraceSources.SetTraceLevel(myItemsControl.ItemContainerGenerator,   System.Diagnostics程序。presentationTraceLevel.High)\ r \的BackSlasHn发件人立即   窗口。这将导致检测逻辑后每运行   CollectionChanged事件,所以它会减慢应用程序。\ r \ N

System.Windows.Controls.ItemContainerGenerator\r\n
System.Windows.Controls.ItemCollection\r\n
System.Windows.Data.ListCollectionView\r\n *
WpfApplication1.ThreadSafeObservableCollection`1[[WpfApplication1.Animal, WpfApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]\r\n(The starred sources are considered more likely to be the cause of the problem.)\r\n\r\nThe most common causes are (a) changing the collection or its Count without raising a corresponding event, and (b) raising an event with an incorrect index or item parameter.\r\n\r\nThe exception's stack trace describes how the inconsistencies were detected, not how they occurred. To get a more timely exception, set the attached property 'PresentationTraceSources.TraceLevel' on the generator to value 'High' and rerun the scenario. One way to do this is to run a command similar to the following:\n
System.Diagnostics.PresentationTraceSources.SetTraceLevel(myItemsControl.ItemContainerGenerator, System.Diagnostics.PresentationTraceLevel.High)\r\nfrom the Immediate window. This causes the detection logic to run after every CollectionChanged event, so it will slow down the application.\r\n"

请参阅私人无效dsofsdkfd(对象发件人,RoutedEventArgs E)功能评论版本2 。 我也尝试过与使用FromCurrentSynchronizationContext的TaskScheduler。


See private void dsofsdkfd(object sender, RoutedEventArgs e) function to the comment Version2. I also tried it with the TaskScheduler using FromCurrentSynchronizationContext.

然后抛出也不例外,但我喜欢在一开始同样的问题,所以只有当每一个循环结束列表框刷新。

Then it throws no exception but I have the same problem like at the beginning, so the list box refreshes only if the for each loop is finished.

我怎样才能实现这个目标列表框更新时,我添加元素?

How I can accomplish that the list box updates when I add an element?

最好的问候

推荐答案

我不会推出自己的ObservableCollection这一点。我只是执行UI线程上。新增的呼叫。

I wouldn't roll my own ObservableCollection for this. I'd just perform the .Add call on the UI thread.

    public void test()
    {
        for (var i = 0; i < 10000; i++)
        {
            // create object
            var animal = new Animal {Name = "test" + i};

            // invoke list.Add on the UI thread
            this.Dispatcher.Invoke(new Action(() => list.Add(animal)));

            // sleep
            System.Threading.Thread.Sleep(1);
        }
    }

请注意,由于你在一个窗口的子类, this.Dispatcher 将对应调度员UI线程。如果将这样的逻辑,比方说,一个模型或视图模型类,你需要明确地捕捉 Dispatcher.Current 的UI线程上的价值,并传递人工调度到后台线程。

Note that since you're in a Window subclass, this.Dispatcher will correspond to the dispatcher for the UI thread. If you move this logic to, say, a model or view model class, you'll need to explicitly capture the value of Dispatcher.Current on the UI thread, and pass that dispatcher manually to the background thread.

编辑:OP要求对使用分派一个FrameworkElement的类以外的更多信息。下面是你将如何做到这一点。通过调用 Dispatcher.CurrentDispatcher 收购UI线程的调度员UI线程。该调度程序,然后直接传递到后台线程程序。

OP asked for more information on using the Dispatcher outside of a FrameworkElement class. Here's how you would do that. The dispatcher for the UI thread is acquired on the UI thread by calling Dispatcher.CurrentDispatcher. That dispatcher is then passed directly into the background thread procedure.

public class MainWindowViewModel
{
    // this should be called on the UI thread
    public void Start()
    {
        // get the dispatcher for the UI thread
        var uiDispatcher = Dispatcher.CurrentDispatcher;

        // start the background thread and pass it the UI thread dispatcher
        Task.Factory.StartNew(() => BackgroundThreadProc(uiDispatcher));
    }

    // this is called on the background thread
    public void BackgroundThreadProc(Dispatcher uiDispatcher)
    {
        for (var i = 0; i < 10000; i++)
        {
            // create object
            var animal = new Animal { Name = "test" + i };

            // invoke list.Add on the UI thread
            uiDispatcher.Invoke(new Action(() => list.Add(animal)));

            // sleep
            System.Threading.Thread.Sleep(1);
        }
    }
}

这篇关于在主题列表框中更新的ObservableCollection的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆