2011-01-06 68 views
2

在我的程序中有一個BackgroundWorker類,用於將圖像預加載到BitmapImage對象。我需要將預加載的圖像傳遞給主應用程序(WPF),並將其複製到另一個BitmapImage對象。這似乎不過是工作,當我嘗試WPF和backgroundworker問題

imgViewer.Source = imgNext; //imgNext is a main app copy of the preloaded image 

時出現錯誤,這意味着該對象(imgNext)被另一個線程擁有,它不能被使用。

任何想法如何擺脫它,並獲得代碼工作?

謝謝大家回答!

事實上,我設法通過在App類中創建一個靜態的BitmapImage來解決這個問題。 使用它之前,我做

App.iNext = null; 

然後我加載實際圖像,並凍結它,所以這個靜態屬性可以從任何地方訪問。當循環重複多次時,賦值爲null將防止'對象被凍結'錯誤。

當然,不存在大量與管理單BGW例如,排隊

(目前我使用我的程序中有兩個BitmapImage的特性也定義ImagesContainer類的任務等工作。我使用它接收來自背景工作者的預載圖像。)

imgNext是在MainWindow中定義的公共變量。 (主線程)

void bwImgLoader_DoWork(object sender, DoWorkEventArgs e) 
     { 
      backgrLoadNextPrevList list = e.Argument as backgrLoadNextPrevList; 
      ImagesContainer result = new ImagesContainer(); 
      if (list.HasNextPath) result.imgPrev = PrepareImage(list.NextPath); 
      if (list.HasPrevPath) result.imgNext = PrepareImage(list.PrevPath); 
      e.Result = result; 
     } 
void bwImgLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      ImagesContainer result = e.Result as ImagesContainer; 
      if (result.imgNext != null) 
      { 
       setNextDelegate s = new setNextDelegate(setNext); 
       object[] t = { result.imgNext }; 
       imgNext.Dispatcher.Invoke(s, t); 
      } 
      // do not take into account this line, just ignore it. 
      //if (result.imgPrev != null) imgPrev = result.imgPrev; 
     } 
     public void setNext(BitmapImage b) 
     { 
      imgNext = b; 
     } 
     public delegate void setNextDelegate(BitmapImage b); 

凍結BitmapImage的幫助只在第一個背景負載(請參閱下面的答案下的評論)。當我第二次調用BackgroundWorker時,發生錯誤,該對象被凍結,無法修改。有沒有辦法解凍它?

或者,有沒有辦法將數據從一個線程複製到另一個線程,而不需要將屬性複製到線程?



修訂

謝謝大家的回答!

事實上,我設法通過在App類中創建一個靜態的BitmapImage來解決這個問題。 使用它之前,我做

App.iNext = null; 

然後我加載實際圖像,並凍結它,所以這個靜態屬性可以從任何地方訪問。當循環重複多次時,賦值爲空可防止錯誤。

當然,還有大量的工作與管理單BGW例如,排隊任務等

但是,這些努力都是值得的結果 - 我的表演得到了+ 125%!謝謝大家!

+0

你有一個空的`抓{} `在那裏封鎖。 – 2011-01-06 21:36:55

+0

重複? http://stackoverflow.com/questions/532740/wpf-how-to-handle-errors-with-a-backgroundworker – 2011-01-07 08:28:28

回答

6

BitmapImageFreezable所以你可以加載它後Freeze()它。這將允許從任何線程訪問。

1

在同一個線程上創建所有UI對象是最容易的。這包括從DispatcherObject降序的任何類,例如BitmapImage

在UI線程上 - 在創建BGW之前 - 捕獲TaskScheduler.FromCurrentSynchronizationContext的結果。你可以把它放在班級的私人成員中。例如:

private TaskScheduler ui; 
public void InitiateBGW() 
{ 
    this.ui = TaskScheduler.FromCurrentSynchronizationContext(); 
    this.bwImgLoader.RunWorkerAsync(); 
} 

在BGW,當你需要訪問BitmapImage功能(爲他們創造或修改它們),但排隊的TaskScheduler這樣的:

private BitmapImage PrepareImage(string path) 
{ 
    // This code runs in a BGW. 

    // Load underlying bitmap (non-UI)... 
    var bitmap = ..; 
    // Prepare the bitmap (non-UI)... 

    return Task.Factory.StartNew(() => 
    { 
    var ret = new BitmapImage(); 
    // Load "bitmap" into "ret" 
    return ret; 
    }, CancellationToken.None, TaskCreationOptions.None, this.ui); 
}