C# - WPF - 从另一个线程上的另一个 class 更新 UI

C# - WPF - Updating the UI from another class on another Thread

我浏览了互联网并找到了一个很好的解决方案,我将其合并到下面的代码中,但是它并不能完全满足我的要求,它只在调用更新时有效,但我想 运行 另一个 class 中的一个方法,然后让该方法调用将向 UI 报告的方法,并仅传递一些信息,因此该模型只是在操作之前更改按钮内容 运行.

使用 Dispatcher,我可以获得 UI 控件进行更新,但是我不只是想这样做,我想执行一些功能然后进行 UI 更新。 所以可能有一些我没有得到的理论,我知道 Invoke 是一个同步操作并且突破了它所做的代码 运行 但是 UI 没有更新。

主窗口 有一个内容为“点击我”

的按钮

代码隐藏

public partial class MainWindow : Window
    {
        public static Button windowButton;
        
        public MainWindow()
        {
            InitializeComponent();
            windowButton = btnStart;
        }

        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            // Run a Process in another class on a different Thread
            ProcessClass processClass = new ProcessClass();
            Task processTask = new Task(() =>
            {
                processClass.DoSomething();
            });
            processTask.Start();
            
        }
    }
}

ProcessClass

class ProcessClass:MainWindow
    {
        
        public static void UpdateUI()
        {
            App.Current.Dispatcher.Invoke(delegate
            {
                windowButton.Content = "CHANGED CONTENT";
            });
        }
        
        public void DoSomething()
        {
            UpdateUI();
            int counter = 0;
            for(int i = 1; i < 100; i++)
            {
                counter += i;
                Thread.Sleep(100);
            }

            MessageBox.Show($"Task Completed, answer is {counter}");
        }
    }

假设Process Class是您自己可以更新的代码,将DoDomething()的签名更改为

public async Task DoSomething(IProgress<string> progress)
{
    progress.Report("Begin DoSomething()");

    var counter = 0;
    for(var i = 1; i < 100; i++)
    {
        counter += i;
        await Task.Delay(100).ConfigureAwait(false);

        progress.Report($"DoSomething() - i = {i}");
    }

    progress.Report($"DoSomething() Completed, answer is {counter}");
}

现在可以编写按钮单击处理程序

private async void btnStart_Click(object sender, RoutedEventArgs e)
{
     // usually you would update some other control such as a TextBlock
     // for the feedback, rather than the button content
     var progress = new Progress<string>(s => btnStart.Content = s);
     ProcessClass processClass = new ProcessClass();
     await processClass.DoSomething(progress).ConfigureAwait(false);
}