2

我试图在我的 UI 的另一个线程上运行一个长时间运行的实例方法,但仍将进度报告回 GUI 线程以更新进度条。我知道有很多方法可以做到这一点,并且有很多关于这个的问题。我拥有的长时间运行的实例方法实际上有两个它自己的事件。它有一个在 PropertyChanged 上触发的事件,用于报告当前已完成的工作和当前需要完成的总工作。它还有一个 OperationCompleted 事件。我打算BackgroundWorker在我的 UI 中使用 a 在单独的线程上运行这个长时间运行的方法。我想弄清楚的是:

如果我为 PropertyChanged 和 OperationCompleted 事件创建事件处理程序,我可以实现它们来引发BackgroundWorker事件吗?这是否允许它们全部在后台线程上运行,并从本质上模拟一个事件冒泡到 UI 线程?下面是一个例子:

class GUI : Form
{
     private BackgroundWorker back = new BackgroundWorker();
     back.WorkerReportsProgress = true;
     back.DoWork += new DoWorkEventHandler(myWork);
     back.ProgressChanged += new ProgressChangedEventHandler(myWork_changed);
     back.RunWorkerCompleted += RunWorkerCompletedEventHandler(myWork_completed);

     /* GUI CODE OMITTED */

     private void button_click(object sender, EventArgs e)
     {
          back.RunWorkerAsync();
     }
     private void myWork(object sender, DoWorkEventArgs e)
     {
          Syncer sync = new Syncer();
          sync.PropertyChanged += new PropertyChangedEventHandler(sync_PropertyChanged);
          sync.OperationCompleted += new EventHandler(sync_OperationCompleted);
          sync.LongRunningMethod();

     }
     private void sync_PropertyChanged(object sender, PropertyChangedEventArgs e)
     {
           //calculations & logic as needed
           back.ReportProgress(calculated);
     }
     //might not be necessary to implement because of how BackgroundWorker functions
     private void sync_OperationCompleted(object sender, EventArgs e)
     {
           back.ReportProgress(100);
     }

     private void myWork_changed(object sender, ProgressChangedEventArgs e)
     {
          //update UI progress bar
     }
     private void myWork_completed(object sender, RunWorkerCompletedEventArgs e)
     {
          //tasks needed @ completion such as hide progress bar
     }

BackgroundWorker那么 Syncer 类的事件会在与'DoWork()方法相同的线程上触发吗?这个线程安全吗?欢迎批评和替代建议!

4

2 回答 2

1

从后台工作线程引发的事件将在该线程上运行并阻塞该线程,并且反过来可以引发 ReportProgress 事件,这些事件也将在该工作线程上运行并阻塞,只要它可以访问对 BackgroundWorker 的引用。

如果您牢记这一点并使用调用调用来更新 UI,它应该可以正常工作。

于 2013-11-12T16:51:08.803 回答
1

Syncer() 类事件将从实际引发它们的任何线程触发。这可能是与 DoWork() 处理程序相同的线程,也可能不是。我们不知道 Syncer() 类的内部工作原理,因此我们无法从您发布的代码中分辨出来。

但是,可以从 Syncer() 事件中调用 ReportProgress()。无论他们在哪个线程上触发,这仍然会导致在主 UI 线程中引发 ProgressChanged() 和 RunWorkerCompleted() 事件(假设 BackgroundWorker() 是由主 UI 线程本身创建的;在这种情况下就是这样)。

您不需要手动 Invoke() 任何东西,这就是首先使用 BackgroundWorker() 的重点......以避免需要这样做。

如果您没有使用 BackgroundWorker() 并通过其内置事件“冒泡”事件,而是将 Syncer() 操作包装在手动线程中,那么是的,您需要手动 Invoke() 更新到图形用户界面。

于 2013-11-12T18:13:57.237 回答