如何使其成为“响应式进度条”的工作原理?

时间:2018-03-11 22:29:01

标签: c# wpf

早上好,我正在尝试编写一个在他的界面中使用进度条的应用程序(在C#,WPF中)。我已经阅读了使用Backgroundworker在不同线程中执行UI任务的必要性。我尝试使用大量信息使其工作,但没有任何反应(程序工作正常,但进度条仅显示在“艰苦工作”的末尾)。

我是土木工程师(不是软件工程师),所以我问是否有人可以帮助我。

namespace SAP2000___Quake_Definitions
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private readonly BackgroundWorker bgWoker = new BackgroundWorker();


    public MainWindow()
    {
        InitializeComponent();

        this.bgWoker.WorkerReportsProgress = true;
        this.bgWoker.WorkerSupportsCancellation = true;

        this.bgWoker.DoWork += bgWorker_DoWork;
        this.bgWoker.ProgressChanged += bgWorker_ProgressChanged;
        this.bgWoker.RunWorkerCompleted += bgWorker_RunWorkerCompleted;
    }

    private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.progBar.Value = e.ProgressPercentage;
    }

    private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bgWorker = (BackgroundWorker)sender;            
        Dispatcher.Invoke(new Action(() => DoTheHardWork()));
    }

    private void processButton_Click(object sender, RoutedEventArgs e)
    {
       this.bgWoker.RunWorkerAsync();
    }

    private void DoTheHardWork()
    {
    switch (this.chckBox2.IsChecked.GetValueOrDefault())
        {
            case true:
            this.bgWoker.ReportProgress(0);
            //more hardwork with inputs from WPF

            case false:
            this.bgWoker.ReportProgress(0);
            //more hardwork with inputs from WPF
        }
    }
}
}

2 个答案:

答案 0 :(得分:2)

这不是你应该如何使用BackgroundWorker。几年前我写了一些示例代码。它应该让你走在正确的轨道上:

#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
    if (!bgwPrim.IsBusy)
    {
        //Prepare ProgressBar and Textbox
        int temp = (int)nudPrim.Value;
        pgbPrim.Maximum = temp;
        tbPrim.Text = "";

        //Start processing
        bgwPrim.RunWorkerAsync(temp);
    }
}

private void btnPrimCancel_Click(object sender, EventArgs e)
{
    if (bgwPrim.IsBusy)
    {
        bgwPrim.CancelAsync();
    }
}

private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
    int highestToCheck = (int)e.Argument;
    //Get a reference to the BackgroundWorker running this code
    //for Progress Updates and Cancelation checking
    BackgroundWorker thisWorker = (BackgroundWorker)sender;

    //Create the list that stores the results and is returned by DoWork
    List<int> Primes = new List<int>();


    //Check all uneven numbers between 1 and whatever the user choose as upper limit
    for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
    {
        //Report progress
        thisWorker.ReportProgress(PrimeCandidate);
        bool isNoPrime = false;

        //Check if the Cancelation was requested during the last loop
        if (thisWorker.CancellationPending)
        {
            //Tell the Backgroundworker you are canceling and exit the for-loop
            e.Cancel = true;
            break;
        }

        //Determin if this is a Prime Number
        for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
        {
            if (PrimeCandidate % j == 0)
                isNoPrime = true;
        }

        if (!isNoPrime)
            Primes.Add(PrimeCandidate);
    }

    //Tell the progress bar you are finished
    thisWorker.ReportProgress(highestToCheck);

    //Save Return Value
    e.Result = Primes.ToArray();
}

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

private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    pgbPrim.Value = pgbPrim.Maximum;
    this.Refresh();

    if (!e.Cancelled && e.Error == null)
    {
        //Show the Result
        int[] Primes = (int[])e.Result;

        StringBuilder sbOutput = new StringBuilder();

        foreach (int Prim in Primes)
        {
            sbOutput.Append(Prim.ToString() + Environment.NewLine);
        }

        tbPrim.Text = sbOutput.ToString();
    }
    else 
    {
        tbPrim.Text = "Operation canceled by user or Exception";
    }
}
#endregion

您必须将所有UI编写工作限制为Progress Report和Run wokrer compelte Events。这些将在创建BGW(应该是UI线程)的线程中自动生成。

请注意,您只能报告不同步骤之间的进度。无论如何,我的优势在于我必须编写循环。但是,如果您有现有代码(如大多数下载或磁盘代码),通常只能在文件之间进行报告。

答案 1 :(得分:0)

我的错误是三个:

  1. 尝试使用“Dispatcher.Invoke(new Action(()=&gt; DoTheHardWork()));”解决与我的线程相关的异常(由#3引起的异常)。
  2. 避免实例化: BackgroundWorker bgWorker =(BackgroundWorker)发件人(谢谢@Christopher)。
  3. 编写一个代码,用于在我的Backgroundworker的DoWork事件句柄中操作UI-Component。 MSDN说:您必须小心不要操纵DoWork事件处理程序中的任何用户界面对象。而是通过ProgressChanged和RunWorkerCompleted事件与用户界面进行通信。尝试此操作时,会发生异常。
  4. 解决点#2和#3,UI完全响应“hardwork”功能(在后台运行)。