WPF 调用在长方法处理期间不起作用

发布于 2024-08-29 02:37:44 字数 413 浏览 7 评论 0原文

在第二个方法 (DoWork) 退出之前,以下方法不会应用 wpf 更改(背景 = 红色):

private void change()
{
    Background = Brushes.Red;
    Dispatcher.BeginInvoke((Action) DoWork);
}

DoWork() 需要几秒钟才能运行,我真的不想将其放入线程中,因为此代码将是在多个地方使用,并且可能会以不同的时间间隔与 Dispatcher 线程进行交互。我尝试调用 Invalidate...() 方法,但无济于事。添加 BeginInvoke() 是为了查看延迟是否允许在调用逻辑之前应用后台更改。通常,逻辑是该方法的一部分。顺便说一句,大部分逻辑是在不同的线程上执行的,不应该阻塞调度程序线程?!

有人可以帮忙吗? 谢谢

The following method does not apply the wpf changes (background = red) until the 2nd method (DoWork) exits:

private void change()
{
    Background = Brushes.Red;
    Dispatcher.BeginInvoke((Action) DoWork);
}

DoWork() takes several seconds to run and I don't really want to put it into a thread, as this code will be used in several places and will probably interact will the Dispatcher thread at various intervals. I've tried calling the Invalidate...() methods, but to no avail. The BeginInvoke() was added to see if the delay would allow the background change to be applied before the logic was called. Typically, the logic would be part of this method. Btw, most of the logic is performed on a different thread and shouldn't block the Dispatcher thread?!

Can someone please help?
Thanks

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

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

发布评论

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

评论(3

月下凄凉 2024-09-05 02:37:44

“Dispatcher”线程是 UI 线程。

当您调用 Dispatcher.BeginInvoke((Action) DoWork); 时,您基本上会阻塞 UI 线程,直到 DoWork 退出,因为它在 UI 线程上运行。

这将阻止 UI 更新,因此您看不到背景变化。

您确实应该考虑将 DoWork 移动到后台线程上,可以直接通过 ThreadPool、BackgroundWorker 或其他方式。这将完全纠正这个问题,并防止您阻塞 UI 线程“几秒钟”(如果您使用调度程序的线程运行它,就会发生这种情况)。

The "Dispatcher" thread is the UI thread.

When you call Dispatcher.BeginInvoke((Action) DoWork);, you're basically blocking the UI thread until DoWork exits, since it's running on the UI thread.

This will prevent the UI from updating, hence you don't see the background change.

You really should consider moving DoWork onto a background thread, either via the ThreadPool directly, a BackgroundWorker, or some other means. That would completely correct this problem, and prevent you from blocking the UI thread for a "few seconds" (which will happen if you run this using the Dispatcher's threading).

呆萌少年 2024-09-05 02:37:44

对于线程之间的通信,我们在 WPF 中提供了 Dispatcher 类。

Dispatcher.Invoke(DispatcherPriority.Normal, (NoArgDelegate)delegate
            {
                ------
            });

For communication between threads, we have the Dispatcher class in WPF.

Dispatcher.Invoke(DispatcherPriority.Normal, (NoArgDelegate)delegate
            {
                ------
            });
沐歌 2024-09-05 02:37:44

BeginInvoke(..) 方法不会阻塞调用,而只是将一条新消息放入队列中以供调度程序线程处理。在您发布的代码中,您无法保证在 DoWorks 启动之前处理背景颜色更改。

您可以降低 DoWork 调用的优先级,以确保首先更改背景:

        private void Button_Click(object sender, RoutedEventArgs e)
    {
        grid.Background = new SolidColorBrush(Colors.Red);
        Dispatcher.BeginInvoke((Action)DoWork, DispatcherPriority.ContextIdle);
    }

    private void DoWork()
    {
        Thread.Sleep(1000);
        btn.Content = "Done";
    }

但这不是人类已知的最佳解决方案。

更好的办法是在单独的线程中继续执行 DoWork。
上面使用线程方法的示例如下所示:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        grid.Background = new SolidColorBrush(Colors.Red);

        Task t = new Task(DoWork);
        t.Start();
    }

    private void DoWork()
    {
        Thread.Sleep(1000);
        // Synchronize calls to the UI elements
        Application.Current.Dispatcher.BeginInvoke((Action)(() => { btn.Content = "Done"; }));

    }

只需记住将对 UI 元素的所有操作发布到 UI 线程即可。

BeginInvoke(..) method does not block the call but it simply put a new message to the queue to process by dispatcher thread. In the code you posted, you have no guarantee that background color change will processed before DoWorks starts.

You can put lower priority to the DoWork call to be sure that background is changed first:

        private void Button_Click(object sender, RoutedEventArgs e)
    {
        grid.Background = new SolidColorBrush(Colors.Red);
        Dispatcher.BeginInvoke((Action)DoWork, DispatcherPriority.ContextIdle);
    }

    private void DoWork()
    {
        Thread.Sleep(1000);
        btn.Content = "Done";
    }

But this is not the best solution known to the mankind.

Better would be to proceed with DoWork in separate thread.
Above example using thread approach will look like this:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        grid.Background = new SolidColorBrush(Colors.Red);

        Task t = new Task(DoWork);
        t.Start();
    }

    private void DoWork()
    {
        Thread.Sleep(1000);
        // Synchronize calls to the UI elements
        Application.Current.Dispatcher.BeginInvoke((Action)(() => { btn.Content = "Done"; }));

    }

Just remember to post all operations on UI elements to the UI thread.

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