如果可以,我如何设置BackgroundWorker(或替代方案)';t将逻辑与主线程分离

本文关键字:分离 线程 何设置 设置 如果可以 BackgroundWorker 方案 | 更新日期: 2023-09-27 18:20:20

我需要为wpf中的进度条使用一个后台工作者,而且我是C#的新手。我读了很多关于它们的文章,我看到我可以创建一个backgroundWorker,并将需要跟踪的逻辑移动到DoWork方法中,但我似乎无法分离逻辑。感谢您的帮助。

编辑这是我在一个更大的程序中遇到的一个问题。我知道有一个从事乘法工作的背景是个坏主意。这只是我能想到的最小的问题,表明我有什么问题/EDIT

该程序只需要取两组数字并将其相乘,但我希望在一个单独的线程中有一个进度条,它与显示我完成百分比的MessageBox同时更新,并用值更新textBlock。

主窗口.xaml.cs

namespace backgroundWorkersWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            double[] group1 = { 1, 2, 3, 4 };
            double[] group2 = { 5, 6, 7, 8 };
            double multipliedNumbers = 0;
            double totalCount = group1.Count() * group2.Count();
            double percentageDone = 0;
            double steps = 0;
            foreach (double x in group1)
            {
                foreach (double y in group2)
                {
                    multipliedNumbers = x * y;

                    txtBlock.Text = multipliedNumbers.ToString();
                    steps++;
                    /*I need this part in a separate thread, but I don't know 
how to easily move this log to a DoWork method without moving everything.*/
                    percentageDone = steps / totalCount * 100;
                    progBar.Value = percentageDone;
                    /*So, if the above part were in a separate thread, 
hopefully I would see my MainWindow with a textblock showing the 
current multiplication value, a messagebox that reports a numerical value
for the percentage, and a progress bar that changes percentage every time 
I close the messagebox. */
                    MessageBox.Show(percentageDone.ToString());
                }
            }
        }
    }
}

主窗口.xaml

<Window x:Class="backgroundWorkersWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock Name="txtBlock"/>
        <ProgressBar Height="20"
                     Width="Auto"
                     Minimum="0"
                     Maximum="100"
                     Name="progBar"/>

    </Grid>
</Window>

因此,概括一下,现在发生的事情是,由于所有事情都在一个线程上,我的MessageBox会显示出来,并向上计数完成的百分比,然后一旦达到100%,它就会打开MainWindow并显示完整的进度条,textBlock会显示最后两个相乘的数字的答案。

我想做的是,让进度条在一个单独的线程中运行,而其他一切都留在当前线程中。

我假设我需要创建一个BackgroundWorker,并以某种方式将更新后的完成百分比值发送给它,但我只能找到后台工作程序的简单示例,在这些示例中,你可以将所有逻辑移动到它们中。

编辑为了澄清,我说过我只想在新线程中显示进度条,但我不介意在新线程也显示其他内容,如计算。我只是没能添加一个后台工作者,而不把程序搞砸,或者把所有逻辑转移到另一个线程。我将添加一些代码来显示我过去犯过的错误类型,以及我不想要的错误/EDIT

我不认为这是重复的,因为我不认为这是重复的,因为我不是在问如何设置BackgroundWorker,而是在问我应该如何分离它的逻辑。例如。

我有一个嵌套的for循环。对我来说,创建一个BackgroundWorker并让我的DoWork方法只包含两个for循环是很简单的。但这些循环中有我不希望在单独的线程中出现的逻辑。我是新手,所以我可能问错了这个问题,但我觉得问如何分离这个逻辑与如何使用后台工作者是一个不同的问题。

编辑

我找到了一个适合我的解决方案。我知道这目前被标记为重复,但我无论如何都会添加我的解决方法,以防有人在试图弄清楚C#线程时偶然发现这一点。

为了回答我的问题,分离逻辑就像创建新函数一样简单。我真的不明白背景工作者是如何工作的,这是我的问题。我不知道如何在后台对我需要的数据进行分区。我在了解有关Async/Await的更多信息时找到了解决方案。Async/Await对我来说更有意义,所以它更容易理解,而且事实证明,在大多数情况下,它似乎应该在BackgroundWorkers上使用。这是我的解决方案。希望这最终能重新打开。

主窗口.xaml

<Window x:Class="backgroundWorkersWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock Name="txtBlock"/>
        <ProgressBar Height="20"
                     Width="Auto"
                     Minimum="0"
                     Maximum="100"
                     Name="progBar"/>
        <TextBlock Name="percentage"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   />

    </Grid>
</Window>

主窗口.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace backgroundWorkersWPF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            double[] group1 = { 1, 2, 3, 4 };
            double[] group2 = { 5, 6, 7, 8 };

            //Now the work I wanted is going to an async function.  And the data I need in the main thread is returned using IProgress<>
            doWork(group1, group2);

        }
        private async void doWork(double[] group1, double[] group2)
        {
            double percentageDone = 0;
            double steps = 0;
            double multipliedNumbers = 0;
            double totalCount = group1.Count() * group2.Count();
            foreach (double x in group1)
            {
                foreach (double y in group2)
                {
                    multipliedNumbers = x * y;

                    txtBlock.Text = "Multiplied Numbers: " + x + " * " + y + " = " + multipliedNumbers.ToString();
                    steps++;
                    var progress = new Progress<int>(updateProgressBar);
                    await System.Threading.Tasks.Task.Factory.StartNew(() => calculatePercentage(steps, totalCount, percentageDone, progress));
                }
            }
        }
        private void calculatePercentage(double steps, double totalCount, double percentageDone, IProgress<int> progress)
        {
            percentageDone = steps / totalCount * 100;
            progress.Report((int)percentageDone);
            MessageBox.Show(percentageDone.ToString());
        }
        private void updateProgressBar(int percentageDone)
        {
            progBar.Value = percentageDone;
            percentage.Text = percentageDone.ToString() + "%";
        }
    }
}

/EDIT

如果可以,我如何设置BackgroundWorker(或替代方案)';t将逻辑与主线程分离

您可以通过调用主线程来更新BackgroundWorker中的UI元素。你可以这样做:

            double[] group1 = { 1, 2, 3, 4 };
            double[] group2 = { 5, 6, 7, 8 };
            double multipliedNumbers = 0;
            double totalCount = group1.Count() * group2.Count();
            double percentageDone = 0;
            double steps = 0;

            var bworker = new BackgroundWorker();
            bworker.DoWork += (s, e) =>
            {
                foreach (double x in group1)
                {
                    foreach (double y in group2)
                    {
                        multipliedNumbers = x * y;
                        steps++;
                        this.Invoke((MethodInvoker)delegate()
                        {
                            txtBlock.Text = multipliedNumbers.ToString();
                            percentageDone = steps / totalCount * 100;
                            progBar.Value = percentageDone;
                        });
                    }
                }
            };
            bworker.RunWorkerAsync();