简体   繁体   中英

WPF multithreading property update does not work async

today I'm gonna try to understand multithreading processes in WPF. So I made a very little WPF application which has only one window. In the window you will find a button and a textbox - nothing else:

<Window x:Class="Multithreading.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Button Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" />
    <TextBox Height="23" Name="txtCounter" VerticalAlignment="Top" Width="120" />
</Grid>

Okay - let's look at my click event:

private void button1_Click(object sender, RoutedEventArgs e)
    {
        ThreadStart ts = delegate
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(Threddy));
        };
        new Thread(ts).Start();
    }

As you can see there is a delegate-method 'Threddy':

public void Threddy()
    {
        for (int i = 0; i < 10000; i++)
        {
            txtCounter.Text = "" + i;
        }
    }

I hope now is clear what I am trying to do: if a user clicks the button, then a new thread should start, which changes my textbox's text. But unfortunately the text changes only one time: at the end.

So - what am I doing wrong? Thanks for your help!

CodeCannibal

I think you are confussing starting your thread async with posting your thread code async.
You want to start another thread and from that update a control on UI thread. WPF wont allow you to update a control created on the UI thread from another thread so you will have to use the dispatcher to post off your control update code to the UI thread. This is the Dispatcher wrapper in Theddy.

private void button1_Click(object sender, RoutedEventArgs e) {
    ThreadStart ts = new ThreadStart(Threddy);
    new Thread(ts).Start();
}  

public void Threddy() {
    for (int i = 0; i < 10000; i++){
        Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => {
            txtCounter.Text = "" + i;
        }));
    }
}

Note that inside the loop you can BeginInvoke OR Invoke.
The former (BeginInvoke) means that Threddy loop will continue to run and doesnt wait for the UI to update - that (UI update) will happen but the loop is not waiting on it. The UI and loop counter both progress but are not necessarily in sync.
The later (Invoke) means that each execution of your loop will wait untill the UI control has actually been updated. The UI and loop counter are synced.

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