线程和收藏修饰WPF / C# [英] Threading and collections modification in WPF / C#

查看:163
本文介绍了线程和收藏修饰WPF / C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在开发的C#/ WPF它访问SQL数据库系统,获取一些数据(约10000项),然后应该更新,用作数据,我使用WPF图表数据点的集合在我的应用程序(的Visifire图表解决方案,万一有人不知道)。

I'm currently developing a system in C# / WPF which accesses an SQL database, retrieves some data (around 10000 items) and then should update a collection of data points that is used as data for a WPF chart I'm using in my application (Visifire charting solution, in case anyone was wondering).

当我写了直线前进,单线程的解决方案,该系统将,你可能期待,挂起的时间花费在应用程序查询数据库,检索数据并呈现图表的时间段。不过,我想使这个任务更快加入了等待的动画给用户,而数据被取出,并使用多线程处理。但是,有两个问题就出来了:

When I wrote the straight-forward, single-threaded solution, the system would, as you might expect, hang for the period of time it took the application to query the database, retrieve the data and render the charts. However, I wanted to make this task quicker by adding a wait animation to the user while the data was being fetched and processed using multithreading. However, two problems arise:


  1. 我无法更新我的收藏和保存使用多线程时,它们同步。我不是很熟悉的调度类,所以我不是很知道该怎么做。

  2. 由于我显然不是处理多线程的非常好,等待动画不会出现(因为UI冻结)。

  1. I'm having trouble updating my collections and keeping them synchronized when using multithreading. I'm not very familiar with the Dispatcher class, so I'm not very sure what to do.
  2. Since I'm obviously not handling the multi-threading very well, the wait animation won't show up (since the UI is frozen).

我M试图找出是否有有效使用多线程对集合的好方法。我发现,微软不得不线程安全的集合但没有似乎适合我的需求。

I'm trying to figure out if there's a good way to use multi-threading effectively for collections. I found that Microsoft had Thread-Safe collections but none seems to fit my needs.

此外,如果任何人有一个很好的参考学习和理解的调度我会非常感激。

Also, if anyone have a good reference to learn and understand the Dispatcher I would highly appreciate it.

编辑:
这里是我想要做的代码片段,也许它可以摆脱对我的问题的一些更多的光线:

Here's a code snippet of what I'm trying to do, maybe it can shed some more light on my question:

private List<DataPoint> InitializeDataSeries(RecentlyPrintedItemViewModel item)
{
    var localDataPoints = new List<DataPoint>();

    // Stopping condition for recursion - if we've hit a childless (roll) item
    if (item.Children.Count == 0)
    {
        // Populate DataPoints and return it as one DataSeries
        _dataPoints.AddRange(InitializeDataPoints(item));
    }
    else
    {
        // Iterate through all children and activate this function on them (recursion)
        var datapointsCollection = new List<DataPoint>();
        Parallel.ForEach(item.Children, child => datapointsCollection = (InitializeDataSeries((RecentlyPrintedItemViewModel)child)));

        foreach (var child in item.Children)
        {    
            localDataPoints.AddRange(InitializeDataSeries((RecentlyPrintedItemViewModel)child));
        }
    }

    RaisePropertyChanged("DataPoints");
    AreDataPointsInitialized = true;

    return localDataPoints;
}



感谢

Thanks

推荐答案

借助调度是用于在单个线程管理的工作项目多队列对象,每个队列有当它应该执行它的工作项不同的优先级。

The Dispatcher is an object used to manage multiple queues of work items on a single thread, and each queues has a different priority for when it should execute it's work items.

调度通常引用WPF的主应用程序线程,并用来安排在不同的 DispatcherPriorities ,以便它们按照特定的顺序执行。

The Dispatcher usually references WPF's main application thread, and is used to schedule code at different DispatcherPriorities so they run in a specific order.

例如,假设你想显示加载图片,加载一些数据,然后隐藏图形。

For example, suppose you want to show a loading graphic, load some data, then hide the graphic.

IsLoading = true;
LoadData();
IsLoading = false;

如果你做这一切在一次,它会锁定您的应用程序,你永远不会看到加载图形。这是因为所有的代码默认情况下,在 DispatcherPriority.Normal 队列中运行,因此在时间它完成运行加载图形将被再次隐藏起来。

If you do this all at once, it will lock up your application and you won't ever see the loading graphic. This is because all the code runs by default in the DispatcherPriority.Normal queue, so by the time it's finished running the loading graphic will be hidden again.

相反,你可以使用调度加载数据和隐藏在比的DispatcherPriority较低的调度优先级图形.Render ,如 DispatcherPriority.Background ,所以发生之前加载,包括渲染加载图形中的其他队列中的所有任务完成获得

Instead, you could use the Dispatcher to load the data and hide the graphic at a lower dispatcher priority than DispatcherPriority.Render, such as DispatcherPriority.Background, so all tasks in the other queues get completed before the loading occurs, including rendering the loading graphic.

IsLoading = true;

Dispatcher.BeginInvoke(DispatcherPriority.Background,
    new Action(delegate() { 
        LoadData();
        IsLoading = false;
     }));



但是,这仍然不是很理想,因为调度引用应用程序的单一UI线程,所以你仍然会当您的长时间运行过程中出现的螺纹锁固起来。

But this still isn't ideal because the Dispatcher references the single UI thread of the application, so you will still be locking up the thread while your long running process occurs.

一个更好的解决方案是使用一个单独的线程你的长期运行的进程。我个人的偏好是使用任务并行库因为它的简单和容易。使用

A better solution is to use a separate thread for your long running process. My personal preference is to use the Task Parallel Library because it's simple and easy to use.

IsLoading = true;
Task.Factory.StartNew(() => 
    {
        LoadData();
        IsLoading = false;
    });



但是,这可能的还是的给你的问题​​,因为WPF对象只能修改从创建它们的线程。

But this can still give you problems because WPF objects can only be modified from the thread that created them.

所以,如果你创建一个的ObservableCollection< D​​ataItem的> 在后台线程,您不能修改该集合在任何地方你的代码比后台线程等。

So if you create an ObservableCollection<DataItem> on a background thread, you cannot modify that collection from anywhere in your code other than that background thread.

典型的解决方案是获取你的数据在后台线程,并返回到一个临时变量为主线,并有主UI线程创建对象,并使用从后台线程获得的数据填充它。

The typical solution is to obtain your data on a background thread and return it to the main thread in a temp variable, and have the main UI thread create the object and fill it with data obtained from the background thread.

这篇关于线程和收藏修饰WPF / C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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