简体   繁体   English

带有进度条WPF的backgroundworker的两个问题

[英]Two issues with backgroundworker with progress bar WPF

I'm using WPF and I have main thread which is GUI (wizard). 我正在使用WPF,我的主线程是GUI(向导)。

When user click Finish on wizard it open second thread which display user progress bar used in background worker. 当用户在向导上单击“完成”时,它将打开第二个线程,显示后台工作程序中使用的用户进度栏。

In Main thread I doing: 在主线程中,我正在做:

MessageWithProgressBar progress = new MessageWithProgressBar();
progress.Show();
createFilesInA();
createFilesInB();
createFilesInC();
createFilesInD();
createFilesInE();
createFilesInF();
createFilesInG();
createFilesInH();
createFilesInI();
createFilesInJ();
createFilesInK();

In each createFiles method I increment by 1 the static variable called currentStep which I used it in background worker as detailed below. 在每个createFiles方法中,我将称为currentStep的静态变量加1,该变量在后台工作程序中使用,如下所示。

In background worker I doing: 在后台工作者中,我正在做:

public partial class MessageWithProgressBar : Window
{
    private BackgroundWorker backgroundWorker = new BackgroundWorker();
    public MessageWithProgressBar()
    {
        InitializeComponent();
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.ProgressChanged += ProgressChanged;
        backgroundWorker.DoWork += DoWork;
        backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
    }

    private void DoWork(object sender, DoWorkEventArgs e)
    {
        Thread.Sleep(100);
        int i = GeneralProperties.General.currentStep;
        if (i > GeneralProperties.General.thresholdStep)
        {
            progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                        new DispatcherOperationCallback(delegate
                                        {
                                            progress.Value = 100;
                                            title.Content = progress.Value.ToString();
                                            return null;
                                        }), null);
            return;
        }
        else
        {
            progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                        new DispatcherOperationCallback(delegate
                                        {
                                            progress.Value = (int)Math.Floor((decimal)(8 * i));
                                            progressLabel.Text = progress.Value.ToString();
                                            return null;
                                        }), null);
        }
    }

    private void ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                        new DispatcherOperationCallback(delegate
                                        {
                                            progress.Value = e.ProgressPercentage;
                                            return null;
                                        }), null);
    }

    private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                        new DispatcherOperationCallback(delegate
                                        {
                                            progress.Value = 100;
                                            title.Content = progress.Value.ToString();
                                            return null;
                                        }), null);
        WindowMsgGenDB msg = new WindowMsgGenDB();
        msg.Show();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        if (backgroundWorker.IsBusy == false)
        {
            backgroundWorker.RunWorkerAsync();
        }
    }
}

The main thread updated variable called currentStep and the second thread used it to report on the main thread progress. 主线程更新了名为currentStep的变量,第二个线程使用它来报告主线程的进度。

The operations of the main thread takes a few seconds (not more 15 seconds) 主线程的操作需要几秒钟(不超过15秒)

I have two issues: 我有两个问题:

  1. I see on progress bar only when currentStep=2 (then the progress is 16) and then the progress is 100, and I don't see every step 我只有在currentStep = 2(当时进度为16)然后进度为100的情况下才能在进度条上看到,并且看不到每一步

  2. At the beginning, the progress bar is freeze and it seems like it stuck. 最初,进度条处于冻结状态,似乎卡住了。

(maybe it connects to the call progress.Show() from the main thread?) (也许它从主线程连接到调用progress.Show()吗?)

Thanks! 谢谢!

As far as I understand your code your background worker is not doing anything, really. 据我了解您的代码,您的后台工作人员实际上没有做任何事情。 It updates the progress once and that's it. 它更新进度一次 ,仅此而已。

Also: using global static variables to communicate between a form and a background worker - ouch... 另外:使用全局静态变量在表单和后台工作人员之间进行通信-哎呀...

Also, you're using it wrong in my opinion. 另外,我认为您使用的是错误的。 The work ( CreateFilesInA ... CreateFilesInK ) should be done by the background worker - that's what it is for. 该工作( CreateFilesInA ... CreateFilesInK )应该由后台工作人员完成-这就是它的作用。 As the main thread will be blocked the way you implemented it, you will not see any updates otherwise. 由于主线程将以实现它的方式被阻止,因此您将看不到任何更新。

The usual way to implement something like this is: 实现这样的通常方法是:

  1. Create progress window and disable UI 创建进度窗口并禁用UI
  2. Start background worker that does stuff in DoWork . 启动在DoWork执行任务的后台工作程序。 In DoWork , after every call to a CreateFilesInXYZ method, call ReportProgress to the the UI be updated. DoWork ,每次调用CreateFilesInXYZ方法后,都将调用ReportProgress来更新UI。
  3. Update stuff in progress window whenever ProgressChanged event is fired 每当触发ProgressChanged事件时,更新进度窗口中的内容
  4. Hide progress window and enable your application's UI when background worker is done 隐藏进度窗口,并在后台工作程序完成后启用应用程序的UI

The way you're doing it it's in no way asynchronous. 您这样做的方式绝不是异步的。 So, actually, your code should look something like this: 因此,实际上,您的代码应如下所示:

public partial class MainWindow : Window
{
    private BackgroundWorker backgroundWorker = new BackgroundWorker();
    private MessageWithProgressBar progressWindow;

    public MainWindow()
    {
        InitializeComponent();
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.ProgressChanged += ProgressChanged;
        backgroundWorker.DoWork += DoWork;
        backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        progressWindow = new MessageWithProgressBar();
        progressWindow.Owner = this;
        progressWindow.Show();

        backgroundWorker.RunWorkerAsync();
    }


    private void DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = (BackgroundWorker)sender;
        int numSteps = 11;
        int currentStep = 0;
        int progress = 0;

        CreateFilesInA();
        currentStep += 1;

        progress = (int)((float)currentStep / (float)numSteps * 100.0);
        worker.ReportProgress(progress);

        CreateFilesInB();
        currentStep += 1;

        progress = (int)((float)currentStep / (float)numSteps * 100.0);
        worker.ReportProgress(progress);

        // All other steps here
        ...
    }

    private void ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressWindow.progress.Value = e.ProgressPercentage;
    }

    private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        progressWindow.Close();

        WindowMsgGenDB msg = new WindowMsgGenDB();
        msg.Show();
    }
}

Please note that the above code goes into your main window! 请注意,以上代码进入了您的主窗口! The MessageWithProgressWindow does not contain any code. MessageWithProgressWindow不包含任何代码。 Maybe the Window_Loaded event handler is not the right place to start the background worker, but you get the picture. 也许Window_Loaded事件处理程序不是启动后台工作程序的正确位置,但是您可以得到图片。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM