我正在 BackgroundWorker 线程中抖动图像,并且需要在图像处理完成后更新 UI。我需要更新的图像与 DitherWorker 存在于同一类中。如何传递 BitmapSource 以避免出现上述错误?
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 在传递之前必须卡住在后台线程中。这是最终的注释代码:
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;
}
}
最佳答案
当您仍在后台线程时,调用 BitmapSource
上的 Freeze()
函数。
这使得对象不可变,因此可以在主线程上使用。
Learn here more about freezable wpf objects.该页面讨论了 Freezables 的许多其他方面,但它也明确指出:“卡住的 Freezable 也可以跨线程共享,......”。如果您问我,WPF 中内置的在后台线程上构建 GUI 元素(例如位图)的功能是排名第一的未充分宣传的 WPF 功能。
关于c# - 从BackgroundWorker返回一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7045707/