0

我正在 WPF 中学习 backgroundworker 类。下面的代码在文件 MainWindow.xaml.cs 中

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;

using System.ComponentModel;

namespace FrontEnd
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private BackgroundWorker backGroundWorker;

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

        private void button1_Click(object sender, RoutedEventArgs e)
        {

            button1.IsEnabled = false;
            Flow pro = new Flow(20,10);
            backGroundWorker.RunWorkerAsync(pro);
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Flow pro = (Flow)e.Argument;
           e.Result = pro.NaturalNumbers();
        }

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

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if ((int)e.Result == 1) MessageBox.Show("DONE");
            progressBar1.Value = 0;
        }
    }
}

下面的代码在文件 Flow.cs 中

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace FrontEnd
{
    class Flow
    {
        long i;
        //private int x,y;
        public int X
        {
            get; set;
        }
        public int Y
        {
            get; set;
        }

        public Flow(int x, int y)
        {
            X = x;
            Y = y;
        }
        public int NaturalNumbers()
        {
            for (i = 0; i < 9999; i++)
            {
                Console.WriteLine(i);
                long iteration = i * 100 / 9999;
                if ((i % iteration == 0) &&
                (backgroundWorker != null) && backgroundWorker.WorkerReportsProgress)
                {
                    backgroundWorker.ReportProgress(iteration);
                }
            }
            return 1;
        }
    }
}

错误:当前上下文中不存在名称“backgroundWorker”

如何使进度条正常工作?

4

2 回答 2

2

这是一个有效的简单示例:

public partial class BackgroundWorkerPage : Page
{
    private readonly BackgroundWorker _worker = new BackgroundWorker();

    public BackgroundWorkerPage()
    {
        InitializeComponent();

        _worker.DoWork += WorkerOnDoWork;
        _worker.WorkerReportsProgress = true;
        _worker.ProgressChanged += WorkerOnProgressChanged;
    }

    private void WorkerOnProgressChanged(object sender, ProgressChangedEventArgs progressChangedEventArgs)
    {
        progressBar.Value = progressChangedEventArgs.ProgressPercentage;
    }

    private void WorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
    {
        for (int i = 0; i <= 100; i++)
        {
            Thread.Sleep(50);
            _worker.ReportProgress(i);
        }
    }

    private void Button_Click_1(object sender, System.Windows.RoutedEventArgs e)
    {
        _worker.RunWorkerAsync();
    }
}

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ProgressBar x:Name="progressBar" Height="23" Minimum="0" Maximum="100"/>
    <Button Grid.Row="1" Height="23" Content="Start" Click="Button_Click_1"/>
</Grid>

你需要稍微改变你的代码

private void WorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
    var flow = new Flow(_worker);
    flow.NaturalNumbers();
}

internal class Flow
{
    private readonly BackgroundWorker _worker;

    public Flow(int x, int y)
    {
        X = x;
        Y = y;
    }

    public Flow(BackgroundWorker worker)
    {
        _worker = worker;
    }

    public int X { get; set; }
    public int Y { get; set; }

    public int NaturalNumbers()
    {
        for (int i = 0; i <= 9999; i++)
        {
            int iteration = i*100/9999;

            // your if(...) fails with divide by zero exception

            _worker.ReportProgress(iteration);
        }

        return 1;
    }
}
于 2012-04-09T09:39:01.477 回答
1

介绍

每当我们尝试在 UI 上执行一些长时间运行的操作而不冻结它时,我们需要在单独的线程中运行它。在本文中,我们将研究 BackgroundWorker 类,作为这个问题的各种解决方案之一,并通过一个简单的示例. BackgroundWorker 在单独的线程上执行操作,并在必要时向 UI 线程提供通知。直接实验

让我们创建一个 UI,如下所示

在此处输入图像描述

目标是,当我们点击“Populate”按钮时,我们应该能够在“Textbox”中写一些东西。

现在让我们看看没有 BackgroundWorker 的代码

public partial class WithOutBackgroundThread : Form
{  
    List<Employee> lstEmp;

    public WithOutBackgroundThread()
    {
        InitializeComponent();
        lstEmp = new List<Employee>();
    }

    private void btnPopulate_Click(object sender, EventArgs e)
    {  
        GetEmployeeRecords();
        dataGridView1.DataSource = lstEmp;
        lblStatus.Text = "Work Completed";
    }

    //Prepare the data
    private void GetEmployeeRecords()
    {
        for (int i = 1; i <= 10; i++)
        {
            // Simulate a pause
            Thread.Sleep(1000);
            lstEmp.Add(new Employee { EmpId = i, EmpName = "Name" + i });
        }
    }
}

代码非常简单。在“GetEmployeeRecords()”方法中,我们正在准备数据。我们引入了“Thread.Sleep(1000)”来进行延迟。在“填充”按钮单击事件中,我们正在填充网格。

但是,如果我们执行此代码,UI 将变得无响应,因此我们无法在“文本框”上执行任何任务,这是我们的目标。

从今以后,让我们将代码更改为以下

public partial class WithBackgroundThread : Form
{
    BackgroundWorker workerThread;
    List<Employee> lstEmp;

    public WithBackgroundThread()
    {
        InitializeComponent();

        lstEmp = new List<Employee>();
        workerThread = new BackgroundWorker();
        workerThread.DoWork += new DoWorkEventHandler(workerThread_DoWork);
        workerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerThread_RunWorkerCompleted);

    }

    private void btnPopulate_Click(object sender, EventArgs e)
    {
        workerThread.RunWorkerAsync(); 
    }

    private void workerThread_DoWork(object sender, DoWorkEventArgs e)
    {
        GetEmployeeRecords();
    }

    private void workerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        lblStatus.Text = "Work Completed";
        dataGridView1.DataSource = lstEmp;
    }

    //Prepare the data
    private void GetEmployeeRecords()
    {
        for (int i = 1; i <= 10; i++)
        {
            // Simulate a pause
            Thread.Sleep(1000);
            lstEmp.Add(new Employee { EmpId = i, EmpName = "Name" + i });
        }
    }
}

很多新的东西。我们将一一探索。

首先,我们需要声明 BackgroundWorker 线程

BackgroundWorker workerThread = new BackgroundWorker();

接下来,我们需要订阅事件

workerThread.DoWork += new DoWorkEventHandler(workerThread_DoWork);
workerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerThread_RunWorkerCompleted);

第三步,我们需要实现这两个方法

private void workerThread_DoWork(object sender, DoWorkEventArgs e)
{
   // run all background tasks here
   GetEmployeeRecords();
}

private void workerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  //update ui once worker complete its work
  lblStatus.Text = "Work Completed";
  dataGridView1.DataSource = lstEmp;
}

当我们调用“RunWorkerAsync”方法时会引发“DoWork”事件。这是我们开始执行潜在耗时工作的操作的地方。当后台操作完成、取消或引发异常时会触发“RunWorkerCompleted”事件

最后一步,从“填充”按钮单击事件中调用“RunWorkerAsync”。

private void btnPopulate_Click(object sender, EventArgs e)
{
    workerThread.RunWorkerAsync(); 
}

“RunWorkerAsync”开始执行后台操作。

现在,如果我们运行我们的应用程序,我们将能够填充网格以及在“文本框”上写一些东西。

在此处输入图像描述

谢谢

于 2013-11-28T09:29:46.313 回答