c# - 从BackgroundWorker返回一个对象

标签 c# c#-4.0

我正在 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/

相关文章:

c# - 以编程方式更改系统日期

c# - 将 SqlDataReader 传递给多个线程时是否应该通过引用传递 SqlDataReader

c# - 在 View 模型中使用 ICommand 可以吗

C# 非常简单的图像缩放器

c# - Entity Framework 对象不为 null 但 `== null` 返回 true

entity-framework - 删除记录 Entity Framework

c# - 按值对 ConcurrentDictionary 进行排序

c#-4.0 - 任务并行库 - 知道所有任务何时完成

asp.net-mvc - VS 2012 中缺少 "Browse With..."按钮

c# - 如何使用 lambda 表达式或使用任何其他逻辑转换数据?