Andrew Stephens
Andrew Stephens

Reputation: 10203

Trying to display a "please wait" message in WPF during a long-running operation

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

Answers (3)

Rachel
Rachel

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

Arsen Mkrtchyan
Arsen Mkrtchyan

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

Abbas
Abbas

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

Related Questions