2013-04-18 35 views
0

這裏是我的問題。
我在一家BlockingCollectionC#WPF從BlockingCollection更新UI源與調度

public void blockingProducer(BitmapImage imgBSource) 
    { 
     if (!collection.IsAddingCompleted) 
      collection.Add(imgBSource); 
    } 

裝載發生在backgroungwork線程負載幾個BitmapImages。

private void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     String filepath; int imgCount = 0; 

     for (int i = 1; i < 10; i++) 
     { 
      imgCount++; 

      filepath = "Snap"; 
      filepath += imgCount; 
      filepath += ".bmp"; 

      this.Dispatcher.BeginInvoke(new Action(() => 
      { 
       label1.Content = "Snap" + imgCount + " loaded."; 
      }), DispatcherPriority.Normal); 

      BitmapImage imgSource = new BitmapImage(); 
      imgSource.BeginInit(); 
      imgSource.UriSource = new Uri(filepath, UriKind.Relative); 
      imgSource.CacheOption = BitmapCacheOption.OnLoad; 
      imgSource.EndInit(); 

      blockingProducer(imgSource); 
     } 
    } 

調試代碼的一切,這部分看起來不錯,現在問題就來了......

完成裝載我想通過一個顯示他們在UI一個圖像之後。我使用的是調度員這樣做,但我總是得到的消息告訴我,因爲它屬於一個不同的線程調用Thread不能訪問該對象。

public void display(BlockingCollection<BitmapImage> results) 
    { 
     foreach (BitmapImage item in collection.GetConsumingEnumerable()) 
     { 
      this.Dispatcher.BeginInvoke(new Action(() => 
      { 
       this.dstSource.Source = item; 
       Thread.Sleep(250); 
      }), DispatcherPriority.Background); 
     } 
    } 

調試指責的錯誤是在這裏

   this.dstSource.Source = item; 

我想一切,但不能找出什麼是錯的。任何人有任何想法?

回答

1

你必須加載圖像,以使它們對其他線程訪問後打電話到Freeze

BitmapImage imgSource = new BitmapImage(); 
imgSource.BeginInit(); 
imgSource.UriSource = new Uri(filepath, UriKind.Relative); 
imgSource.CacheOption = BitmapCacheOption.OnLoad; 
imgSource.EndInit(); 
imgSource.Freeze(); // here 

據我理解了BitmapCacheOption.OnLoad標誌,它是唯一有效的當的BitmapImage從流中加載。在BitmapCacheOption說明部分說:

設置CacheOption到BitmapCacheOption.OnLoad如果你想關閉用於創建的BitmapImage一個 流。直到需要的圖像的默認緩存按需選項 保留訪問流,並且 清理是由垃圾收集處理。

從Uri創建的BitmapImage可能會異步加載(請參閱IsDownloading屬性)。因此,Freeze可能不是這樣的BitmapImage的調用,因爲下載可能仍在EndInit後的進展。我猜它仍然工作在你的情況,因爲你是從裝載檔案URI,這似乎是立即進行BitmapImages。

爲避免你可能只是從一個FileStream創建的BitmapImage這個潛在的問題:

var imgSource = new BitmapImage(); 

using (var stream = new FileStream(filepath, FileMode.Open)) 
{ 
    imgSource.BeginInit(); 
    imgSource.StreamSource = stream; 
    imgSource.CacheOption = BitmapCacheOption.OnLoad; 
    imgSource.EndInit(); 
    imgSource.Freeze(); 
} 
+0

嗨,謝謝你的作品。最後一個問題。將圖像加載到BlockingCollection後,我開始顯示它們,但只顯示最後一幅圖像。有什麼想法發生了什麼?謝謝。 – Probst 2013-04-18 13:12:19

+0

這當然是因爲您在傳遞給分派器的委託方法內執行了Sleep調用。你必須在BeginInvoke之前調用它。但是,更好的解決方案是使用[DispatcherTimer](http://msdn.microsoft.com/zh-cn/library/system.windows.threading.dispatchertimer.aspx)逐個顯示圖像。 – Clemens 2013-04-18 15:31:46

+0

嗨克萊門斯,我刪除了睡眠,但它仍然無法正常工作。奇怪的事實是,當我第二次調用加載線程時,圖像被顯示。但是一旦我調用顯示函數,什麼都不會發生。 所以我第一次運行程序只顯示最後一張圖像。從現在起,每次我調用加載線程時,都會顯示圖像,並且當我調用顯示線程時什麼都不會發生。 – Probst 2013-04-18 15:52:54

0

爲進一步未來的讀者,這裏是我用來解決我的問題的代碼。

public void display(BlockingCollection<BitmapImage> collection) 
    { 
     if (collection.IsCompleted || collection.Count != 0) 
     { 
      BitmapImage item = collection.Take(); 
      this.Dispatcher.BeginInvoke(new Action(() => 
      { 
       this.dstSource.Source = item; 

      }), DispatcherPriority.Normal); 
     } 
     else 
     { 
      dispatcherTimer.Stop(); 
     } 
    } 

    public void dispatcherTimer_Tick(object sender, EventArgs e) 
    { 
     display(collection); 
    } 

    public void configureDispatcherTimer() 
    { 
     dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick); 
     TimeSpan interval = TimeSpan.FromMilliseconds(150); 
     dispatcherTimer.Interval = interval; 
    }