Reputation: 10203
I have a please wait
TextBlock
in my XAML whose Visibility
property is bound to an IsBusy
property on my ViewModel (which implements INotifyPropertyChanged
). A separate button launches a long-running (2-3 seconds) process, like this:
IsBusy = true;
try
{
// Do some long-running process
}
finally
{
IsBusy = false;
}
But the please wait
message never appears. I'm assuming the operation is running on the UI thread and therefore not giving it a chance to refresh? It does work if I run the above code on a separate thread, but I don't want the user to do anything while the operation is running - I'm happy for the UI to freeze
.
How can I display the please wait
message? Or would I be better running it on a background thread and (somehow) locking the UI for the duration? I'm using .Net 4 btw.
Upvotes: 4
Views: 4182
Reputation: 132568
You're correct, it's not updating because you're running the code on the same thread, so rendering doesn't continue until after your process has finished.
You said you aren't using a background thread because you don't want the user to do anything while the operation is running, but it's never a good idea to completely lock up your application like this.
A better solution would be to bind the IsEnabled
of your Form/Window/UserControl/etc to the IsBusy
property. Then when it becomes busy, the entire form gets disabled to prevent the user from modifying it, while not locking up your application.
Upvotes: 5
Reputation: 50752
At first Visibility
property is not bool
, so if you want to bind bool
variable to it you need to use IValueConverter
,and second, yes you are right, while UI thread is busy with your long running operation it will not execute anything else including visibility change.
I would suggest to use WPF Toolkit
BusyIndicator
expect of putting your own panel, it have IsBusy bool
property.
Also froozen UI is not user friendly, generally I use this snippet
IsBusy = true;
Task.Factory.StartNew(() =>
{
// Do work.
})
.ContinueWith(t=>IsBusy=false,
TaskScheduler.FromCurrentSynchronizationContext());
Also note to check errors in ContinueWith
method, or you will get exception on Task
dispose
Upvotes: 1
Reputation: 14432
If you run your code on a separate thread, you can still access the UI through the Dispatcher.BeginInvoke Method.
if (!YOURCONTROL.Dispatcher.CheckAccess())
{
YOURCONTROL.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(delegate()
{
//do something with the control/form/...
}));
}
else
{
//update your control
}
Upvotes: 0