0

In wpf Suppose I have a counter label, in code behind I tried to increment the value every 3 seconds but it doesn't work, I mean something like:

XAML:

<Label x:Name="MyLabel" Content="Label" />

Code behind:

public MyClass()
{
 Task t = Task.Factory.StartNew(() =>
        {
            int i = 1;
            while (true)
            {
                MyLabel.Content=i;
                Thread.Sleep(3000);
                i++;
            }
        });
}

Output: the label stays the same

Flufy
  • 309
  • 2
  • 15

1 Answers1

1

WPF UIElement can only be accessed in a single Thread. So you cannot access or modify the value of the <Label/>.

But WPF also provides a thread model named Dispatcher, you can get the Dispatcher of the UIElement and invoke your action into the original thread.

What you should do is to change MyLabel.Content=i into MyLabel.Dispatcher.InvokeAsync(() => MyLabel.Content = i);.

This is the whole code:

Task.Run(async () =>
{
    int i = 1;
    while (true)
    {
        // Note: this works because the thread slept 3000ms.
        // If the thread doesn't sleep, we should declare a new variable
        // so that i will not change when the action invokes.
        // That means `var content = i;`
        // Then `MyLabel.Dispatcher.InvokeAsync(() => MyLabel.Content = content);`
        await MyLabel.Dispatcher.InvokeAsync(() => MyLabel.Content = i);
        await Task.Delay(3000);
        i++;
    }
});

I change your synchronized call to async call and this is recommended.


You'll find that Dispatcher.InvokeAsync is very useful when you're trying to update UI in the background thread. Furthermore, you can add DispatcherPriority parameter to determine the running priority of all the actions you invoked.

walterlv
  • 2,366
  • 13
  • 73