本文介绍了数据绑定到BlockingCollection的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试实现以下要求(C#4.0);

I am trying to implement the following requirements (C# 4.0);


  • 一个生产者 $ b
  • 处理请求(FIFO)的一个消费者,并保持UI更新为项状态更新或请求已满足。

  • One "producer" (on the UI thread - driven by user action) which submits upload requests
  • A ListView control which is databound to the collection of pending upload requests
  • One consumer which process the requests (FIFO), and keeps the UI up-to-date as items status' update, or the request is fulfilled.

到目前为止,我还没有使用两个集合来实现上面的操作,如下:

So far, I haven't been able to work out how to do the above without using two collections, as follows;

public void AddUploadRequest(UploadRequest uploadRequest)
{
    this.UploadRequests.Add(uploadRequest);
    this.uploadRequestsBlocking.Add(uploadRequest);
}

...其中 UploadRequests ObservableCollection< UploadRequest> uploadRequestsBlocking BlockingCollection< UploadRequest& code>

... where UploadRequests is an ObservableCollection<UploadRequest> and uploadRequestsBlocking is a BlockingCollection<UploadRequest>

完整的代码可以在这里找到; (忽略Dispatcher的总注入 - 这只是到目前为止的原型代码)

The full code can be found here; http://pastebin.com/620EqaY5 (ignore the gross injection of Dispatcher - this is just prototype code so far)

我通知我的UI有关更新,如下所示:

I notify my UI of updates as follows;

this.dispatcher.Invoke(() => this.UploadRequests.Remove(uploadRequest));

有更好的方法来实现这个功能吗?

Is there a better way to achieve this functionality? Or, more importantly, are there any serious drawbacks to this approach?

我考虑的一个可能的扩展是有多个用户,通过使用 Parallel .ForEach over GetConsumingPartitioner (基于 example)。关于当前方法的任何东西会使这不适合吗?它确实可以工作,但我不是100%有信心,我没有犯过一些重要的线程人造角色在途中的某个地方。

One possible extension I was considering was to have multiple consumers, by using Parallel.ForEach over GetConsumingPartitioner (based on this example). Would anything about the current approach make this unsuitable? It does work OK, but I'm not 100% confident that I haven't committed some major threading faux-pas somewhere along the way.

推荐答案

不能只是将数据绑定到BlockingCollection的主要(唯一)原因是它不实现INotifyCollectionChanged,因此当添加/删除请求时UI不会更新。也就是说,在网络上有 BlockingCollection包装器实现INotifyCollectionChanged。或者,您可以为BlockingCollection公开一个CollectionView,而不是从ObservableCollection分派一个删除,只需分派CollectionView的刷新。

The main (only) reason that you can't just databind to the BlockingCollection is that it does not implement INotifyCollectionChanged, so the UI would not get updated when a request is added / removed. That said, there are BlockingCollection wrappers around on the net that implement INotifyCollectionChanged. Or you could instead expose a CollectionView for the BlockingCollection and instead of dispatching a remove from an ObservableCollection, just dispatch a Refresh of the CollectionView.

    public ICollectionView UploadRequestsView {get;set;}

    public UploadRequester(Dispatcher dispatcher)
    {
        this.dispatcher = dispatcher;           
        this.uploadRequestsBlocking = new BlockingCollection<UploadRequest>();

        UploadRequestsView = CollectionViewSource.GetDefaultView(uploadRequestsBlocking);

        this.consumerTask = Task.Factory.StartNew(this.ConsumeUploadRequests);
    }

    public void AddUploadRequest(UploadRequest uploadRequest)
    {
        uploadRequestsBlocking.Add(uploadRequest);
        UploadRequestsView.Refresh()
    }

    private void ConsumeUploadRequests()
    {
        foreach (var uploadRequest in this.uploadRequestsBlocking.GetConsumingEnumerable())
        {
            uploadRequest.Status = "Uploading...";

            Thread.Sleep(2000);
            uploadRequest.Status = "Successfully uploaded";

            Thread.Sleep(500);
            dispatcher.Invoke(() => UploadRequestsView.Refresh());
        }
    }

这篇关于数据绑定到BlockingCollection的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-28 00:22