2011-08-12 94 views
2

我抖動BackgroundWorker線程中的圖像,並且需要在完成圖像處理後更新UI。我需要更新的圖像與DitherWorker存在於同一個類中。如何傳遞BitmapSource以避免發生指出的錯誤?從BackgroundWorker返回一個對象

public void DitherWorker() 
{ 
    double scalebox = Double.Parse(myWindow.scaleBox.Text); 
    int slider = (int)myWindow.convolutionBiasSlider.Value; 
    BitmapSource final = null; 
    ditherobj output = new ditherobj(scalebox, originalImage, slider);//.Get_Halftone(); 

    worker = new BackgroundWorker(); 
    worker.WorkerSupportsCancellation = true; 

    worker.DoWork += delegate(object s, System.ComponentModel.DoWorkEventArgs args) 
    { 
     ditherobj dob = (ditherobj)args.Argument; 
     Binarize bn = new Binarize(dob.scalebox, dob.localbms, dob.slider); 
     BitmapSource bms = (BitmapSource)bn.Get_Halftone(); 
     final = bms; 
     args.Result = new ditherobj(0,null,0,bms); 
    }; 

    worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args) 
    { 
     ditherobj dob = (ditherobj)args.Result; 
     image1.Source = dob.localbms; //ERROR. The calling thread cannot access this object because another thread owns it 

     myWindow.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() => 
     { 
      myWindow.activityBar.IsBusy = false; 
     })); 
    }; 

    worker.RunWorkerAsync((ditherobj)output); 
} 

public class ditherobj 
    { 
     public double scalebox; 
     public BitmapSource localbms; 
     public BitmapImage localbmi; 
     public int slider; 

     public ditherobj(double scalebox, BitmapImage localbmi, int slider, BitmapSource bms = null) 
     { 
      this.scalebox = scalebox; 
      this.slider = slider; 
      if (bms == null) 
      { 
       BitmapImage test = localbmi.Clone(); 
       localbms = (BitmapSource)test; 
      } 
      else 
       localbms = bms; 
     } 
    } 

問題解決了。在傳遞之前,BitmapSource必須在後臺線程中凍結。下面是最終comented代碼:

BackgroundWorker worker; 
    public void DitherWorker() 
    { 
     double scalebox = Double.Parse(myWindow.scaleBox.Text); //get values from UI for the job 
     int slider = (int)myWindow.convolutionBiasSlider.Value; 
     DitherSettings output = new DitherSettings(scalebox, originalImage, slider); //create holder object to be passed to BackgroundWorker 
     worker = new BackgroundWorker(); 

     worker.DoWork += delegate(object s, System.ComponentModel.DoWorkEventArgs args) 
     { 

      DitherSettings ds = (DitherSettings)args.Argument; //cast argument as our holder object 
      Binarize bn = new Binarize(ds.scalebox, ds.localbms, ds.slider); //create object to do our work 
      BitmapSource bms = (BitmapSource)bn.Get_Halftone(); //do work 
      bms.Freeze(); //freeze resulting BitmapSource so it can be utilized elsewhere 
      args.Result = new DitherSettings(0,null,0,bms); //create new object with resulting BitmapSource 

     }; 

     worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args) 
     { 
      DitherSettings ds = (DitherSettings)args.Result; //get object with our BitmapSource 

      if (image1.Dispatcher.CheckAccess()) 
       this.image1.Source = ds.localbms; //update class image 

      myWindow.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() => 
      { 
       myWindow.activityBar.IsBusy = false; //Update UI control 
      })); 
     }; 

     worker.RunWorkerAsync((DitherSettings)output); 

    } 

    public class DitherSettings 
    { 
     public double scalebox; 
     public BitmapSource localbms; 
     public BitmapImage localbmi; 
     public int slider; 

     public DitherSettings(double scalebox, BitmapImage localbmi, int slider, BitmapSource bms = null) 
     { 
      this.scalebox = scalebox; 
      this.slider = slider; 
      if (bms == null) 
       localbms = (BitmapSource)localbmi; 
      else 
       localbms = bms; 
     } 
    } 
+0

什麼是'ditherobj'?線程所有權和所有權轉移的概念不是.NET的核心;如果這是第三方庫,您使用的是哪個庫?或者這是你的班級? – Jacob

+0

一個容易傳遞值的簡單對象。編輯帖子以顯示此內容。 – PhilJ

+0

爲什麼'ditherobj'類/ struct沒有命名爲'DitherSettings'? –

回答

3

呼籲BitmapSourceFreeze()功能,當你仍然在後臺線程。

這使得對象不可變,因此可以在主線程上使用。

Learn here more about freezable wpf objects.該頁面討論了Freezables的許多其他方面,但它也明確指出:「凍結的Freezable也可以跨線程共享......」。在WPF中構建的在後臺線程上構建GUI元素(比如位圖)的功能是如果你問我,那麼就是#1 underadvertized WPF功能。

+0

謝謝,Freeze()做到了。 – PhilJ

0

BitmapSource.Clone()如果您想複製對象,可能會有一些用處。

Dispatcher.CheckAccess()應該在設置image1之前調用。

+0

太棒了,在設置圖像之前添加了CheckAccess()。 – PhilJ