WPF Dispatcher并在后台运行它

时间:2009-06-10 11:40:53

标签: c# wpf multithreading dispatcher

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

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

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

7 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:2)

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

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

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

答案 2 :(得分:2)

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

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

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

如果Runner.Action的长时间运行部分正在更新GUI而不是使用后台线程来解决您的问题 - 有慢速GUI操作的解决方案,但它们会根据您的具体操作而改变。

答案 3 :(得分:1)

这是一个允许您运行具有多个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();

答案 4 :(得分:1)

同样在座的人都说过了。

此外,您可能希望使用BackgroundWorker类。

答案 5 :(得分:1)

这是我开始用于后台任务的...我没有长时间使用它,所以我不知道是否有错误。

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) {

}

答案 6 :(得分:0)

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