【问题标题】:Is it possible to Update UI from 2 background workers是否可以从 2 个后台工作人员更新 UI
【发布时间】:2014-01-01 00:01:33
【问题描述】:

我正在使用 C# 开发 WPF 应用程序,并且我想实现第二个后台工作对象。我已经有 1 个按我想要的方式工作了。

第一个后台工作人员根据一些操作更新进度条。 我希望第二个更新显示倒计时的文本块。

首先,这可能吗? 目前,当计时器倒计时到零时,当其他线程尝试访问进度条时,会报错。

调用线程无法访问此对象,因为另一个线程拥有它。

这是我的后台工作人员的代码: 在主窗口方法中我初始化它们。

        // Add the background worker events
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.WorkerReportsProgress = true;

        worker_timer.DoWork += worker_TrackTime;
        worker_timer.RunWorkerCompleted += worker_TimeCompleted;
        worker_timer.ProgressChanged += worker_timerProgressChanged;
        worker_timer.WorkerReportsProgress = true;

这里是线程方法:

private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        // Run all background tasks here
        copyEverything(sourceFolder, targetFolder);
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // Update UI once worker complete his work
        // Update the progress bar and progress percent text to the max value it can be
        copy_progressbar.Value = copy_progressbar.Maximum;
        copy_textblock.Text = copy_progressbar.Maximum + "%";

        worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        worker.DoWork -= new DoWorkEventHandler(worker_DoWork);
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        // Update something here
        copy_progressbar.Value = e.ProgressPercentage;
        copy_textblock.Text = e.ProgressPercentage + "%";

        // Check if the progressbar has reached its maximum value, if so set the value to its max
        if (copy_progressbar.Value >= copy_progressbar.Maximum)
        {
            copy_progressbar.Value = copy_progressbar.Maximum;
            copy_textblock.Text = copy_progressbar.Maximum + "%";
        }
    }

    private void worker_TimeCompleted(object sender, RunWorkerCompletedEventArgs e)
    {

    }

    private void worker_TrackTime(object sender, DoWorkEventArgs e)
    {
        while (true)
        {
            Thread.Sleep(1000);
            elapsedTS = elapsedTS.Add(new TimeSpan(0, 0, 1));
            try
            {
                worker_timer.ReportProgress(1);
            }
            catch
            {
            }

            if (elapsedTS >= schedule.TS)
            {
                copyEverythingAsync(sourceFolder, targetFolder);
                schedule.updateSchedule(DateTime.Now, false);
                schedule.checkSchedule();
                checkScheduleTime();

                elapsedTS = TimeSpan.Zero;
            }
        }
    }

    private void worker_timerProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        time_left_textblock.Text = "" + schedule.TS.Subtract(elapsedTS).ToString(@"dd\.hh\:mm\:ss");
        //time_left_textblock.Text = "" + schedule.TS.Subtract(elapsedTS).ToString();
    }

跟踪计时器的线程没有完成的方法,因为我希望它继续运行。

如果需要,我可以提供更多信息。

【问题讨论】:

  • 在 ProgressChangedEventArgs e 中传递 elapsedTS。不要尝试直接访问它。
  • 始终检查 Completed 事件中的错误。
  • 这个问题与后台worker的数量无关。您的标题暗示出现此问题是因为这是第二部作品。但事实上,问题在于,您正在尝试更新 UI - 如果您只有 1 个后台工作人员正在执行此操作,您会看到相同的错误。正如 Mayank 指出的那样,您需要分派回 UI 线程以更新 UI。
  • @IanGriffiths BGW 的整个 是代表您为除DoWork 事件之外的所有事件处理程序编组到UI 线程。所以不,您不需要“总是需要手动分派回 UI 线程”。
  • 您不应该在一段时间后使用 BGW 来运行某些代码。您应该为此使用Timer。由于这是专为您正在尝试做的工作而设计的工具,您会发现它更容易使用。至于您看到的错误,您没有显示足够的代码来复制问题。

标签: c# wpf multithreading backgroundworker


【解决方案1】:

您需要使用 UI 线程更新 UI。

   private void worker_timerProgressChanged(object sender, ProgressChangedEventArgs e)
    {
       Dispatcher.Invoke(() => 
       {
          time_left_textblock.Text = "" + schedule.TS.Subtract(elapsedTS).ToString(@"dd\.hh\:mm\:ss");
       });
    }

【讨论】:

  • 它说 Invoke 在当前上下文中不存在。我是否缺少命名空间?
  • 为 WPF 调用 Dispatcher.Invoke
  • 您的回答有效。当它尝试更新 UI 时,我只需要在另一个线程上使用 Dispather.Invoke。谢谢
  • 使用 BGW 的整个要点是它会代表您将非工作事件编组到 UI 线程,因此您不需要 /i> 做这样的事情。
  • @Servy 更合适的方法是什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-21
相关资源
最近更新 更多