从其他线程更新UI

时间:2009-04-07 10:24:38

标签: winforms multithreading asynchronous

我知道之前已经问过这个问题,但我觉得没有正确询问。

我有一个密集的操作,我希望UI保持响应。我已经阅读了一些帖子,说背景工作者是最好的方法,但是,我认为这假设你有密集任务的源代码。

我有一个我没有源代码的库,我可以检查进度的唯一方法是附加到被触发的事件并获取信息。

我在MSDN网站上看到的例子假设有一个来源。

我知道如何通过附加到事件来获得进度(这是一个百分比值),但是如何将该值返回到UI?

4 个答案:

答案 0 :(得分:2)

以下答案基于我的直觉,并没有真正用第三方库进行测试。

  • 像往常一样调用您的第三方lib代码,在简单的背景(而不是BackGroundWorker)线程中调用。
  • 将库组件的事件附加到代码中的普通事件处理程序(用于更新UI)。
  • 在事件中,处理程序代码应如下所示:

    private void EventHandler(object sender, DirtyEventArgs e)
    {
        if (myControl.InvokeRequired)
            myControl.Invoke(new MethodInvoker(MethodToUpdateUI), e);
        else
            MethodToUpdateUI(e);
    }
    
    private void MethodToUpdateUI(object obj) 
    {
        // Update UI
    }
    

答案 1 :(得分:1)

附加到第三方组件中的进度事件,并在BackgroundWorker上致电ReportProgress。让您的UI附加到BackgroundWorker.ProgressChanged事件以更新UI。

答案 2 :(得分:0)

通过使用第二个线程和线程安全队列,您可以获得所需的效果。

您可以创建一个侦听事件的第二个线程。 当新事件发生时,它会将事件信息推送到队列(线程安全同步)。

使用定时器(Windows.Forms.Timer)每隔x次检查一次该队列,如果存在新事件,可以更新UI。

因为计时器在主线程中运行,所以它可以安全地更新UI,如果你重量轻,它就不会阻塞它足够长的时间以便被注意到。

答案 3 :(得分:0)

关于this Q的类似讨论。如果您出于某种原因无法或不想使用BackgroundWorker,您可以使用自己的线程并将事件中的事件编组回UI线程。

private void Initialise() {      
    MyLibClass myLibClass = new MyLibClass();
    myLibClass.SomeEvent += SomeEventHandler;
    ThreadPool.QueueUserWorkItem(myLibClass.StartLongTask);
}


private void SomeEventHandler(EventArgs e) {     
   if (this.Dispatcher.Thread != Thread.CurrentThread) { 
      this.Dispatcher.Invoke(delegate { DoStuffOnUIThread(e); });
   }
   else {        
       DoStuffOnUIThread(e);     
   }
}
相关问题