简体   繁体   中英

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

I have looked around the internet and found a nice solution which I am incorporating into my code below however it doesn't quite do exactly what I want, it works when just calling an update but I want to run a method in another class then let that method call the method that will report back to the UI and just pass some information so this mock up is just changing the button content before the operation is ran.

Using a Dispatcher I can get a UI control to update however I don't just wish to do that I want to perform some functions then have the UI Update. So there maybe some theory I am not getting, I know the Invoke is a synchronous operation and breaking through the code it does run but the UI doesn't update.

MainWindow Has a single button with content "CLICK ME"

Code Behind

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}");
        }
    }

Assuming that ProcessClass is your own code that you can update, change the signiture of DoDomething() to

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}");
}

Now your button click handler can be written

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM