Reputation: 8291
This question is somehow asked in many threads here, but I couldn't find a clear answer to my case, I have a simple code, a Button
, a Textbox
and a ButtonClickEventHandler
, this latter despite being Async
, keeps the UI blocking, code :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Task t = new Task(() =>
{
for (int i = 0; i < 10000; i++)
{
Dispatcher.Invoke((()=>
{
TextBox.Text += i.ToString();
}));
}
});
t.Start();
await t;
//Something else
}
}
Xaml :
<Window x:Class="WpfApplication1.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 Margin="180,10,185,277" x:Name="Button" Click="ButtonBase_OnClick">
Ok
</Button>
<TextBox Margin="29,83,40,33" x:Name="TextBox"></TextBox>
</Grid>
</Window>
First, why is this happening ? Second, what I should I do to make the UI keeps working normally without hanging, always by following this logic.
Upvotes: 0
Views: 198
Reputation: 456322
As others have noted, if you attempt to update your UI too frequently, you will end up blocking user interaction.
As far as your code goes, you should be using Task.Run
instead of the task constructor, and IProgress<T>
instead of Dispatcher.Invoke
. I have an IProgress<T>
implementation that handles throttling for you, which can be used as such:
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
using (var progress = ObservableProgress<int>.CreateForUi(value => UpdateUi(value)))
{
await Task.Run(() => BackgroundOperation(progress));
}
...
}
private static void UpdateUi(int progressUpdate)
{
TextBox.Text += progressUpdate.ToString();
}
private static void BackgroundOperation(IProgress<int> progress)
{
for (int i = 0; i < 10000; i++)
{
if (progress != null)
progress.Update(i);
}
}
No artificial delays necessary.
Upvotes: 5
Reputation: 70652
Define "blocked". The code you posted will not block the UI. But it will sure keep it really busy, which may well have the effect of it seeming like it's blocked. And for that matter, blocking it for all practical purposes even though it's not really.
You're basically executing a denial-of-service attack on your GUI thread. You've got a secondary thread in a tight loop that just keep executing stuff on the GUI thread. Don't do that and things will be much better.
Upvotes: 5