【问题标题】:Updating UI from a different thread从不同的线程更新 UI
【发布时间】:2010-10-18 00:29:25
【问题描述】:

我知道以前有人问过这个问题,但我觉得问得不对。

我有一个密集的操作,我希望 UI 保持响应。我读过一些帖子说后台工作人员是最好的方法,但是,我认为这是假设您拥有执行密集任务的源代码。

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

我在 MSDN 网站上看到的示例假设有源代码。

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

【问题讨论】:

    标签: winforms multithreading asynchronous


    【解决方案1】:

    附加到第三方组件中的进度事件并在BackgroundWorker 上调用ReportProgress。将您的 UI 附加到 BackgroundWorker.ProgressChanged 事件以更新 UI。

    【讨论】:

      【解决方案2】:

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

      • 像往常一样调用您在简单后台(不是 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
        }
        

      【讨论】:

      • 使用Invoke方法是直接传入方法名还是需要先创建委托?
      • 检查更改。您可以使用 MethodInvoker 委托。只有方法名是不够的。
      【解决方案3】:

      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);     
         }
      }
      

      【讨论】:

        【解决方案4】:

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

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

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

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

        【讨论】:

        • @Vince - 如果您无权访问“Control”类并且不想创建一个虚拟类来抛出事件,那么它可能是在主线程中抛出事件的唯一方法
        猜你喜欢
        • 1970-01-01
        • 2014-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多