【问题标题】:WPF Dispatcher and Running it in backgroundWPF Dispatcher 并在后台运行它
【发布时间】:2009-06-10 11:40:52
【问题描述】:

我试图将调度程序包装在一个线程中。但结果不是我所期望的。我该如何解决这个问题?

    public void Start()
    {
        ThreadStart ts = inner;
        Thread wrapper = new Thread(ts);
        wrapper.Start();
    }

    private void inner()
    {
        _Runner.Dispatcher.Invoke(_Runner.Action, DispatcherPriority.Normal);
    }

【问题讨论】:

  • 结果是什么,你的期望是什么
  • 期望:调度程序和在后台运行它也尝试了 BeginInvoke。结果是一样的。当开始从客户端调用时(单击按钮等)线程的运行和结束。但是客户端在进程运行时不能做任何事情。

标签: c# wpf multithreading dispatcher


【解决方案1】:

您没有向我们展示足够多的代码/没有很好地解释自己,无法提供一个好的答案,但我猜测您的操作 (_Runner.Action) 代价高昂且执行缓慢。如果是这样,这就是您的 UI 没有响应的原因。您实际上是在告诉 Dispatcher 在 UI 线程上运行该昂贵的操作,而您真正想做的是在后台线程上尽可能多地运行您的操作,然后通过 Dispatcher 编组回 UI 线程仅在必要时。

【讨论】:

  • 后台线程如果立即调用调度程序在UI线程上执行任务,则无济于事。
【解决方案2】:

当您通过/在调度程序上触发操作时,会在 UI 线程上调用该操作。

我的猜测是您正在 _Runner.Action 函数中进行工作/处理,它正在占用 UI 线程。您必须在 inner() 函数中执行主要处理部分,然后调用 Dispatcher 以获取最终更新详细信息。

如果您绝对必须在调度程序上进行处理,请将您的流程分成更小的部分,并为每个部分调用 Dispatcher.BeginInvoke(),以便在您的流程之间处理其他事件。

【讨论】:

    【解决方案3】:

    您需要将 Runner.Action 分成两部分 - 执行计算的长时间运行部分和更新 GUI 的部分。

    完成此操作后,您在后台线程中调用长时间运行的部分,并仅在 UI 更新部分使用调度程序。

    顺便说一句,您也应该使用 BeginInvoke 而不是 Invoke。

    如果 Runner.Action 的长时间运行部分正在更新 GUI,那么您就不能使用后台线程来解决您的问题 - 对于缓慢的 GUI 操作有一些解决方案,但它们会根据您正在尝试做什么而改变。

    【讨论】:

      【解决方案4】:

      这是一个示例,可让您使用多个 UI 线程运行 WPF 应用程序。我相信这会对你有所帮助。参考这个http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/

      Thread lThread = new Thread(() =>
                         {
                              var lWnd = new Window1();
                              lWnd.Show();
                              lWnd.Closed += (sender2, e2) => lWnd.Dispatcher.InvokeShutdown();
                              System.Windows.Threading.Dispatcher.Run();
                         });
      lThread.SetApartmentState(ApartmentState.STA);
      lThread.Start();
      

      【讨论】:

        【解决方案5】:

        这里的每个人都说过。

        此外,您可能想考虑使用 BackgroundWorker 类。

        【讨论】:

          【解决方案6】:

          这是我开始用于后台任务的……我用的时间不长,所以不知道有没有bug。

          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Text;
          
          namespace SSA.Utility
          {
              public class BackgroundTaskManager : IDisposable
              {
                  private System.Windows.Threading.Dispatcher _OwnerDispatcher;
                  private System.Windows.Threading.Dispatcher _WorkerDispatcher;
                  private System.Threading.Thread _WorkerThread;
                  private Boolean _WorkerBusy;
          
                  private System.Threading.EventWaitHandle _WorkerStarted = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset);
          
                  public BackgroundTaskManager()
                  {
                      _OwnerDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
                      _WorkerThread = new System.Threading.Thread(new System.Threading.ThreadStart(WorkerStart));
                      _WorkerThread.Name = "BackgroundTaskManager:" + DateTime.Now.Ticks.ToString();
                      _WorkerThread.IsBackground = true;
                      _WorkerThread.Start();
          
                      _WorkerStarted.WaitOne();
                  }
          
                  public Boolean IsBusy
                  {
                      get { return _WorkerBusy; }
                  }
          
                  public System.Windows.Threading.Dispatcher Dispatcher 
                  {
                      get {
                          return _WorkerDispatcher;
                      }
                  }
          
                  public System.Windows.Threading.Dispatcher OwnerDispatcher
                  {
                      get
                      {
                          return _OwnerDispatcher;
                      }
                  }
          
          
                  private void WorkerStart()
                  {
                      _WorkerDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
                      _WorkerDispatcher.Hooks.DispatcherInactive += WorkDone;
                      _WorkerDispatcher.Hooks.OperationPosted += WorkAdded;
                      _WorkerStarted.Set();
                      System.Windows.Threading.Dispatcher.Run();
                  }
          
                  private void WorkAdded(Object sender, System.Windows.Threading.DispatcherHookEventArgs e)
                  {
                      _WorkerBusy = true;
                  }
          
                  private void WorkDone(Object sender, EventArgs e)
                  {
                      _WorkerBusy = false;
                  }
          
                  public void Dispose()
                  {
                      if (_WorkerDispatcher != null)
                      {
                          _WorkerDispatcher.InvokeShutdown();
                          _WorkerDispatcher = null;
                      }
                  }
          
              }
          }
          
          
          // Useage (not tested)
          
          private SSA.Utility.BackgroundTaskManager _background = new SSA.Utility.BackgroundTaskManager();
          
          public void LongTaskAsync() 
          {
            _background.Dispatcher.BeginInvoke(new Action(LongTask), null);
          }
          
          public void LongTask() 
          {
             System.Threading.Thread.Sleep(10000); // simulate a long task
             _background.OwnerDispatcher.BeginInvoke(new Action<STATUSCLASS>(LongTaskUpdate), statusobject);
          }
          
          public void LongTaskUpdate(STATUSCLASS statusobject) {
          
          }
          

          【讨论】:

          • 这似乎是一种非常复杂的创建后台任务的方法。我会使用 BackgroundWorker。 msdn.microsoft.com/en-us/library/…
          • 我承认它对大多数事情来说都是多余的,但我喜欢使用它的语法与普通调度程序相同,我喜欢优先级功能。我将它用于工作项队列而不是单个操作。 BackgroundWorker 没有内置功能。最初的问题是关于这个实现的新线程中的调度程序。
          • 如果你能把你的答案的本质分开,或许分享一些有用的补充建议,答案会好得多。无论如何,感谢您的分享,欢迎来到 SO!
          【解决方案7】:

          是的。 _Runner.Action 是问题所在。 Dispatcher 块中使用的一些长时间的方法。但解决方案是“不要在调度程序中使用与 UI 无关的任何线程”

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-04-02
            • 1970-01-01
            • 1970-01-01
            • 2012-09-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多