2010-10-19 73 views
2

我跟着this tutorial創建一個優先級隊列,並用阻塞集合包裝它。我有一個DataGrid,它連接到發出變化事件的基礎優先級隊列。我可以通過UI線程將項目添加到集合中,並且可以阻止緩衝區滿足其應有的時間。BlockingCollection + UI線程

現在我該如何消耗這些物品?下面是我有:

public DownloadViewModel() 
{ 
    Queue = new ConcurrentPriorityQueue<DownloadItem>(10); 
    Buffer = new BlockingCollection<KeyValuePair<int, DownloadItem>>(Queue, 10000); 

    Task.Factory.StartNew(() => 
    { 
     KeyValuePair<int, DownloadItem> item; 
     while(!Buffer.IsCompleted) 
     { 
      if(Buffer.TryTake(out item)) 
      { 
       // do something with the item 
      } 

      Thread.SpinWait(100000); 
     } 
    }); 
} 

但只要我添加了Task.Factory.StartNew位,我的應用程序突然需要30秒出現的窗口前(之前它是瞬發),當我做添加一個項目,我得到例外

此類CollectionView不支持從與分派器線程不同的線程更改其SourceCollection。

我明白了,但是真的需要使用UI線程來獲取項目嗎?這並不能擊敗使用此BlockingCollection的整個目的嗎?我想創建4個或8個消費者並讓他們並行運行。

這應該怎麼做?

+0

它真的非常有必要只從UI線程更新UI控件。這是例外情況告訴你的。是的,這很快就會破壞精心製作的線程方案的實用性。 – 2010-10-19 20:12:26

+0

@Hans:當然,但是當阻塞隊列嘗試接收一個項目時,底層隊列會發出更改通知,..爲什麼不能自動將其委派回UI線程?消費者爲什麼要被阻止?無論如何,我願意接受任何sol'n現在,即使它的效率比我認爲應該低一點。我想這是一個很常見的範例。生產者 - 消費者不是什麼新鮮事,向用戶顯示剩餘物品應該不那麼困難? – mpen 2010-10-19 20:28:34

+0

談到穿線時,沒有什麼是自動的或簡單的。將結果收集到列表中,並使用Dispatcher.BeginInvoke更新UI。 – 2010-10-19 20:38:46

回答

2

中包裝CollectionChanged事件W /調度程序似乎工作得很好......

public bool TryAdd(KeyValuePair<int, T> item) 
{ 
    int pos = _queues.Take(item.Key + 1).Sum(q => q.Count); 
    _queues[item.Key].Enqueue(item.Value); 
    Interlocked.Increment(ref _count); 
    Dispatcher.BeginInvoke(
     new Action(
      () => 
      NotifyCollectionChanged(
       new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, pos)) 
     )); 
    return true; 
} 

剛把我從ConcurrentPriorityQueue派生DispatcherObject。我認爲這是它應該如何完成的。


更方便的是,只寫NotifyCollectionChanged方法是這樣的:

private void NotifyCollectionChanged(NotifyCollectionChangedEventArgs e) 
{ 
    lock (CollectionChanged) 
    { 
     if (CollectionChanged != null) 
      Dispatcher.BeginInvoke(new Action(() => CollectionChanged(this, e))); 
    } 
} 

然後你不必亂拋垃圾的其他方法與BeginInvoke

+0

你可能會發布代碼示例(MainWindow.xaml.cs)嗎? – Fulproof 2013-03-14 03:36:35

+0

@Fulproof:找不到使用此類的示例,但以下是完整的類:http://goo.gl/9BWb7 – mpen 2013-03-14 04:55:23

+0

謝謝,但您提供的類代碼給出編譯錯誤「對象引用是必需的非靜態字段,方法或屬性'System.Windows.Threading.Dispatcher.Invoke(System.Delegate,params object [])'「 – Fulproof 2013-03-14 06:55:59

0

[評論的問題,在此之後]

你並不需要「採取使用UI線程的項目」。但是,由於處理消費任務中的項目而導致對UI的任何更新都需要分派到UI線程。分開您的擔憂!