使用 C# 的 WPF 中的多线程(使用后台工作程序)

发布于 2024-09-26 14:02:39 字数 1718 浏览 4 评论 0原文

我编写了代码来保存应用程序生成的图像。图像大小约为 32-35 MB。将图像保存到 BMB 文件时,需要很长时间,大约 3-5 秒。为此,我使用了后台工作程序,但在运行后台工作程序时,它显示一个错误,例如...“无法访问该对象,因为它是在不同线程上创建的”。

以下是代码:

 private void btnSaveDesign_Click(object sender, RoutedEventArgs e)
    {
        Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog();
        sfd.Title = "Save design as...";
        sfd.Filter = "BMP|*.bmp";
        if (sfd.ShowDialog() == true)
        {
            ww = new winWait();
            ww.Show();
            System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();
            bw.DoWork += new System.ComponentModel.DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            fName = sfd.FileName;
            cache = new CachedBitmap((BitmapSource)imgOut.Source, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);

            bw.RunWorkerAsync();


        }  
    }

    void bw_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        ww.Close();
    }

    void bw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        BmpBitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(cache)); //here... it says cant access...
        using (FileStream file = File.OpenWrite(fName))
        {
            encoder.Save(file);
        }
    }

我已将“缓存”声明为全局对象。 (当我使用 VB.NET 在 Windows 窗体中进行编程时,类似的技巧起作用了。)

ww 是我希望在执行过程时显示的等待窗口。

如何做到这一点? WPF中还有其他简单的多线程方法吗?

I have written code to save an image which is generated by the application. The size of the image is around 32-35 MB. While saving the image to a BMB file, it is taking a long time, around 3-5 secs. For this purpose, I have used a background worker but when running the background worker, it shows an error like..."can't access the object as it is created on different thread".

Following is the code:

 private void btnSaveDesign_Click(object sender, RoutedEventArgs e)
    {
        Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog();
        sfd.Title = "Save design as...";
        sfd.Filter = "BMP|*.bmp";
        if (sfd.ShowDialog() == true)
        {
            ww = new winWait();
            ww.Show();
            System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();
            bw.DoWork += new System.ComponentModel.DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            fName = sfd.FileName;
            cache = new CachedBitmap((BitmapSource)imgOut.Source, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);

            bw.RunWorkerAsync();


        }  
    }

    void bw_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        ww.Close();
    }

    void bw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        BmpBitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(cache)); //here... it says cant access...
        using (FileStream file = File.OpenWrite(fName))
        {
            encoder.Save(file);
        }
    }

I have declared "cache" as a global object. (A similar trick worked when I was programming in Windows Forms with VB.NET.)

ww is the wait window that I want to be displayed while the precess is being executed.

How to do this? Is there any other simple method for multi threading in WPF?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

兔姬 2024-10-03 14:02:39

创建 WPF 对象时,它们被分配给 Dispatcher 对象。这不允许除创建线程之外的任何线程访问该对象。可以通过调用 freeze 方法冻结对象来避免这种情况。您需要对位图源对象调用 Freeze。一旦你冻结了你的对象,它就变得不可编辑

When WPF objects are created they are assigned to a Dispatcher object. This disallows any threads other than the creating thread to access the object. This can be circumvented by freezing the object by calling the freeze method. You would need to call Freeze on your bitmapsource object. Once you have frozen your object it becomes uneditable

难如初 2024-10-03 14:02:39

出现您的问题是因为您正在访问不是由后台工作线程创建的对象。通常,如果您访问在主线程中创建并从不同线程访问的 UI 控件,就会发生这种情况。

使用下面的代码。

Dispatcher.Invoke
(
    new Action(
        delegate()
        {
            BmpBitmapEncoder encoder = new BmpBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(cache));
            using (FileStream file = File.OpenWrite(fName))
            {
                encoder.Save(file);
            }
        }
    )
);

Your problem comes about because you are accessing an object which is not created by the background worker thread. Normally this would happen if you access a UI control which is created in the main thread and accessed from different thread.

Use the code below.

Dispatcher.Invoke
(
    new Action(
        delegate()
        {
            BmpBitmapEncoder encoder = new BmpBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(cache));
            using (FileStream file = File.OpenWrite(fName))
            {
                encoder.Save(file);
            }
        }
    )
);
凉月流沐 2024-10-03 14:02:39

我认为你必须将缓存作为参数传递给新线程:

bw.RunWorkerAsync(cache);

并从 DoWork 方法获取它:

var cache=(CacheType) e.Argument;

I think you have to pass cache as a parameter to the new thread:

bw.RunWorkerAsync(cache);

and get it from the DoWork method:

var cache=(CacheType) e.Argument;
一瞬间的火花 2024-10-03 14:02:39

.NET 框架提供了一种开始线程处理的简单方法
后台工作组件。这包含了大部分的复杂性和
使得生成后台线程相对安全。此外,它
允许您在后台线程和 UI 之间进行通信
线程无需执行任何特殊编码。您可以使用该组件
与 WinForms 和 WPF 应用程序。 BackgroundWorker 提供
几个功能,包括生成后台线程、
能够在后台进程完成之前取消它,以及
有机会向您的用户界面报告进度。

public BackgroudWorker()
            {
                InitializeComponent();
                backgroundWorker = ((BackgroundWorker)this.FindResource("backgroundWorker"));
            }

            private int DoSlowProcess(int iterations, BackgroundWorker worker, DoWorkEventArgs e)
            {            
                int result = 0;
                for (int i = 0; i <= iterations; i++)
                {
                    if (worker != null)
                    {
                        if (worker.CancellationPending)
                        {
                            e.Cancel = true;
                            return result;
                        }
                        if (worker.WorkerReportsProgress)
                        {
                            int percentComplete =
                            (int)((float)i / (float)iterations * 100);
                            worker.ReportProgress(percentComplete);
                        }
                    }
                    Thread.Sleep(100);
                    result = i;
                }
                return result;
            }

            private void startButton_Click(object sender, RoutedEventArgs e)
            {
                int iterations = 0;
                if (int.TryParse(inputBox.Text, out iterations))
                {
                    backgroundWorker.RunWorkerAsync(iterations);
                    startButton.IsEnabled = false;
                    cancelButton.IsEnabled = true;
                    outputBox.Text = "";
                }

            }

            private void cancelButton_Click(object sender, RoutedEventArgs e)
            {
                // TODO: Implement Cancel process
                this.backgroundWorker.CancelAsync();
            }

            private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
            {
               // e.Result = DoSlowProcess((int)e.Argument);

                var bgw = sender as BackgroundWorker;
                e.Result = DoSlowProcess((int)e.Argument, bgw, e);
            }

            private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                workerProgress.Value = e.ProgressPercentage;
            }

            private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                if (e.Error != null)
                {
                    MessageBox.Show(e.Error.Message);
                }
                else if (e.Cancelled)  
                {
                    outputBox.Text = "Canceled";
                    workerProgress.Value = 0;
                }
                else
                {
                    outputBox.Text = e.Result.ToString();
                    workerProgress.Value = 0; 
                }
                startButton.IsEnabled = true;
                cancelButton.IsEnabled = false;
            }

.NET framework provides a simple way to get started in threading with
the BackgroundWorker component. This wraps much of the complexity and
makes spawning a background thread relatively safe. In addition, it
allows you to communicate between your background thread and your UI
thread without doing any special coding. You can use this component
with WinForms and WPF applications. The BackgroundWorker offers
several features which include spawning a background thread, the
ability to cancel the background process before it has completed, and
the chance to report the progress back to your UI.

public BackgroudWorker()
            {
                InitializeComponent();
                backgroundWorker = ((BackgroundWorker)this.FindResource("backgroundWorker"));
            }

            private int DoSlowProcess(int iterations, BackgroundWorker worker, DoWorkEventArgs e)
            {            
                int result = 0;
                for (int i = 0; i <= iterations; i++)
                {
                    if (worker != null)
                    {
                        if (worker.CancellationPending)
                        {
                            e.Cancel = true;
                            return result;
                        }
                        if (worker.WorkerReportsProgress)
                        {
                            int percentComplete =
                            (int)((float)i / (float)iterations * 100);
                            worker.ReportProgress(percentComplete);
                        }
                    }
                    Thread.Sleep(100);
                    result = i;
                }
                return result;
            }

            private void startButton_Click(object sender, RoutedEventArgs e)
            {
                int iterations = 0;
                if (int.TryParse(inputBox.Text, out iterations))
                {
                    backgroundWorker.RunWorkerAsync(iterations);
                    startButton.IsEnabled = false;
                    cancelButton.IsEnabled = true;
                    outputBox.Text = "";
                }

            }

            private void cancelButton_Click(object sender, RoutedEventArgs e)
            {
                // TODO: Implement Cancel process
                this.backgroundWorker.CancelAsync();
            }

            private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
            {
               // e.Result = DoSlowProcess((int)e.Argument);

                var bgw = sender as BackgroundWorker;
                e.Result = DoSlowProcess((int)e.Argument, bgw, e);
            }

            private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                workerProgress.Value = e.ProgressPercentage;
            }

            private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                if (e.Error != null)
                {
                    MessageBox.Show(e.Error.Message);
                }
                else if (e.Cancelled)  
                {
                    outputBox.Text = "Canceled";
                    workerProgress.Value = 0;
                }
                else
                {
                    outputBox.Text = e.Result.ToString();
                    workerProgress.Value = 0; 
                }
                startButton.IsEnabled = true;
                cancelButton.IsEnabled = false;
            }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文