当UI在Task.Wait()上时,使用Dispatcher强制UI线程更新控件

本文关键字:UI Dispatcher 使用 强制 更新 控件 线程 上时 Task Wait | 更新日期: 2023-09-27 17:53:30

是否有可能强制UI线程停止等待任务完成,通过Dispatcher更新UI控件,然后让UI恢复到等待任务完成?

我刚刚尝试了下面的代码,但它不工作,因为它出现

UpdatePB(int NewValue) 

方法正在被非UI线程执行。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Threading;
using System.Windows.Threading;
using System.Windows.Threading;
namespace UpdateControlViaDispatcherUITaskWaitAll
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public void UpdatePB(int NewValue)
        {
            pb1.Value = NewValue;
        }

        private void btn1_Click(object sender, EventArgs e)
        {
            Task tk = Task.Factory.StartNew(() =>
            {
                Worker();
            });
            tk.Wait();
        }
        public void Worker()
        {
            int currentValue = 0;
            for (int i = 0; i < 100; i++)
            {
                currentValue = i;
                Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
                {
                    UpdatePB(currentValue);
                }));

                Thread.Sleep(1000);
            }
        }
    }
}

当UI在Task.Wait()上时,使用Dispatcher强制UI线程更新控件

避免阻塞UI线程:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Task.Factory
        .StartNew(this.Worker)
        .ContinueWith(this.OnWorkerCompleted);
}
public void Worker()
{
    Dispatcher.Invoke(new Action(() =>
    {
        btn1.IsEnabled = false;
    }));
    // your stuff here...
}
private void OnWorkerCompleted(Task obj)
{
    Dispatcher.Invoke(new Action(() =>
    {
        btn1.IsEnabled = true;
    }));
}

尽量减少对Dispatcher的调用,并尝试使用BackgroundWorker,它支持后台线程和UI线程之间的自动同步与ProgressChanged和RunWorkerComplete事件。

WPF DispatcherDispatcherOperation的任务队列,所以当你调用tk.Wait();时,它会阻塞Dispatcher线程,直到tk完成。您无法暂停此等待并再次恢复,但只能取消DispatcherOperation。但在你的情况下,我认为你最好禁用按钮(或整个窗口),并在tk完成时启用它。所以您应该考虑异步等待tk完成。