2013-03-19 58 views
1

我想加載幾個圖像異步到用戶界面。創建和更新用戶界面元素異步Wpf

加載圖像時(位圖是從路徑創建的),應該將圖像設置爲窗口上矩形的填充。

當我將Bitmapimage的創建也放在Dispatcher.Invoke方法中時,代碼就可以工作。但顯然,我想要花費大量工作(創建位圖),而不是調用。

我已經嘗試了幾個解決方案,其中包括backgroundworker,但我無法讓它工作。現在,我有以下代碼:

private void Window_ContentRendered(object sender, EventArgs e) 
{ 
    Thread loadThread = new Thread(new ThreadStart(LoadImagesAsync)); 
    loadThread.Start(); 
} 

private void LoadImagesAsync() 
{ 
    IEnumerable<string> images = System.IO.Directory.GetFiles(IMAGE_FOLDER, "*.jpg").Skip(_PageNumber * NUMBER_OF_IMAGES).Take(NUMBER_OF_IMAGES); 

    for (int i = 0; i < NUMBER_OF_IMAGES; i++) 
    { 
     var bitm = new BitmapImage(new Uri(images.ElementAt(i)));     

     this.Dispatcher.Invoke(() => 
     { 
      Grid grid = (Grid)grd_photoBox.Children[i]; 

      var rectangle = (from e in grid.Children.OfType<Rectangle>() 
           where e is Rectangle 
           select e).First(); 

      ImageBrush brush = new ImageBrush(bitm); 

      rectangle.Fill = brush; 
     }); 
    } 
} 

我得到以下異常:

The calling thread cannot access this object because a different thread owns it. 

任何線索?

+0

你能描述一下它是如何「不工作」當你把創建位圖的調用之外? – Kohanz 2013-03-19 17:40:15

+0

無效的操作異常被拋出,我編輯我的問題 – middelpat 2013-03-19 17:42:40

+0

我建議看看這個:http://stackoverflow.com/questions/1924408/invalid-cross-thread-access-issue – Kohanz 2013-03-19 18:00:16

回答

3

在大圖像的情況下,使用下面的代碼,它會直接重新調整圖像和加載其他線程,則主線程這可以確保圖像的即時加載。編輯下面的值來改變負載格式:

bitm.DecodePixelWidth = 200; 
bitm.DecodePixelHeight = 100; 

private void LoadImagesAsync() 
     { 
      IEnumerable<string> images = System.IO.Directory.GetFiles(IMAGE_FOLDER, "*.jpg").Skip(_PageNumber * NUMBER_OF_IMAGES).Take(NUMBER_OF_IMAGES); 

      for (int i = 0; i < NUMBER_OF_IMAGES; i++) 
      { 
       int j = i; 
       var bitm = new BitmapImage(); 

       bitm.BeginInit(); 
       bitm.CacheOption = BitmapCacheOption.OnLoad; 
       bitm.UriSource = new Uri(images.ElementAt(i)); 
       bitm.DecodePixelWidth = 200; 
       bitm.DecodePixelHeight = 100; 
       bitm.EndInit(); 

       ImageBrush brush = new ImageBrush(bitm); 
       brush.Freeze(); 

       this.Dispatcher.BeginInvoke(new Action(() => 
       { 
        Grid grid = (Grid)grd_photoBox.Children[j]; 

        var rectangle = (from e in grid.Children.OfType<Rectangle>() 
             where e is Rectangle 
             select e).First(); 

        rectangle.Fill = brush; 
       })); 
      } 
     } 
+1

請小心設置'DecodePixelWidth'或'DecodePixelHeight',因爲它可能會降低某些情況下的性能。請參閱備註[此處](http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.decodepixelwidth.aspx):'JPEG和便攜式網絡圖形(PNG)編解碼器本地解碼將圖像轉換爲指定的大小;其他編解碼器以原始大小對圖像進行解碼並將圖像縮放到所需的大小。如果你想保留圖像的原始高寬比,你通常不應該同時設置。 – Clemens 2013-03-20 17:49:22

+0

還可以注意到,如果需要調用標記爲異步的方法,那麼該操作也必須標記爲異步,新動作(async()=> – GaelSa 2017-03-21 09:46:21

0

我試過下面的代碼,它是爲我工作。

Task<IEnumerable<string>>.Factory.StartNew(() => System.IO.Directory.GetFiles(
      imagePath, 
      "*.jpg")). 
      ContinueWith(task => 
         { 
          foreach (var item in task.Result) 
          { 
           this.Dispatcher.BeginInvoke((Action)(() => 
           { 
            var img = new Image 
                { 
                 Source = 
                  new BitmapImage(
                  new Uri(item)) 
                }; 
            LayoutRoot.Children.Add(img); 

           })); 

          } 
         }); 

LayoutRoot是我在xaml中的網格。

希望它會有所幫助。

+0

謝謝你的回答。它確實有效,但仍然在Invoke中通過uri創建位圖。這會導致在UI線程中創建位圖。使用大圖像時,仍然會導致UI te塊 – middelpat 2013-03-19 18:45:10

1

訣竅是freeze位圖允許從另一個線程訪問。因此,您還必須確保在創建時立即加載位圖,因爲默認行爲是延遲加載。

var bitm = new BitmapImage(); 
bitm.BeginInit(); 
bitm.CacheOption = BitmapCacheOption.OnLoad; // load immediately 
bitm.UriSource = new Uri(images.ElementAt(i)); 
bitm.EndInit(); 
bitm.Freeze(); 
+0

默認行爲是根據[MSDN](http://msdn.microsoft.com/zh-cn/library/system.windows.media)的「BitmapCacheOption.Default」。 image.bitmapcacheoption.aspx)「將整個圖像緩存到內存中。」 – SynerCoder 2013-03-20 09:25:33

+0

@SynerCoder請參閱備註部分[此處](http://msdn.microsoft.com/zh-cn/library/system.windows.media.imaging。 bitmapimage.cacheoption.aspx)。雖然它描述了從流中加載圖像時的行爲,但它通常適用。和[這裏](http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapcacheoption.aspx)你可以閱讀'OnLoad'「緩存整個圖像到內存**加載時間**「,與」默認「中的」將整個圖像緩存到內存中「相反。 – Clemens 2013-03-20 17:32:09

+0

@SynerCoder然而,你最終不需要在這裏應用標誌,因爲圖像是從文件加載的,這似乎是立即完成的。您可以檢查[IsDownloading](http://msdn.microsoft.com/zh-cn/library/system.windows.media.imaging.bitmapimage.isdownloading.aspx)屬性以查明圖像是否正在下載或不在。只要下載,就不能凍結它。 – Clemens 2013-03-20 17:44:50