WPF 调度程序并在后台运行

发布于 2024-07-23 02:57:12 字数 327 浏览 6 评论 0原文

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

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

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

I tried to wrap the dispatcher in a thread. But the result is not what i expect. How can i solve that problem?

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

奢华的一滴泪 2024-07-30 02:57:12

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

You have not shown us enough code/explained yourself well enough to be able to provide a good answer, but I'm guessing your action (_Runner.Action) is expensive and slow to execute. If so, that is why your UI is unresponsive. You're essentially telling the Dispatcher to run that expensive operation on the UI thread when what you really want to do is run as much of your operation on the background thread as possible, and then marshal back to the UI thread via the Dispatcher only when necessary.

乄_柒ぐ汐 2024-07-30 02:57:12

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

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

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

When you fire an action through/on the dispatcher, that action is called on the UI thread.

My guess is that you are doing the work/processing in the _Runner.Action function and it is tying up the UI thread. You'll have to do the main processing part in the inner() function and then call the Dispatcher for the final update details.

If you absolutely must process on the dispatcher, break your process into smaller pieces and call Dispatcher.BeginInvoke() for each piece so other events can be processed in between your process.

花海 2024-07-30 02:57:12

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

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

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

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

You need to break Runner.Action into two parts - the long running part that does the calculation and the part that updates the GUI.

After you do that you call the long running part in the background thread and use the dispatcher only on the UI update part.

By the way, you should also probably use BeginInvoke and not Invoke.

If the long running part of Runner.Action is updating the GUI than you can't use a background thread to solve your problem - there are solutions for slow GUI operations but they change depending on what exactly you are trying to do.

肩上的翅膀 2024-07-30 02:57:12

下面是一个示例,可让您运行具有多个 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();

Here is an example that will let you run WPF applications with multiple UI threads. I believe this will help you. Refer to this 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();
战皆罪 2024-07-30 02:57:12

同上,这里每个人都说过。

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

Ditto what everyone here has said.

Additionally, you may want to look into using the BackgroundWorker class.

姜生凉生 2024-07-30 02:57:12

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

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

}

This is what I have started using for background tasks... I have not been using it long, so I don't know if there are bugs.

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

}
巷子口的你 2024-07-30 02:57:12

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

Yes. _Runner.Action is the problem. Some long-timed methods used in the Dispatcher block. But solution is "dont use the any thread not related to UI in the dispatcher"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文