views:

339

answers:

5

We have a WPF app (actually a VSTO WPF app). On certain controls there are multiple elements which, when clicked, load data from a web service and update the UI. Right now, we carry out these web requests synchronously, blocking the UI thread until the response comes back. This prevents the user clicking around the app while the data is loading, potentially putting it into an invalid state to handle the data when it is returned.

Of course the app becomes unresponsive if the request takes a long time. Ideally, we'd like to have the cancel button active during this time, but nothing else. Is there a clever way of doing this, or will we have to switch the requests to execute asynchronously using backgroundworker and write something that disables all the controls apart from the cancel button while a request is in progress?

edit: for actions we already expect to be long running (downloading a file etc.) we pop up a progress dialog window. The case in point is when you expect the action to be pretty fast (a couple of seconds at most) but occasionally take longer. In those circumstances, flashing up a whole window for a moment is a bit too distracting.

+1  A: 

While you make your Asynchronous request on a seperate thread, show a Modal Dialog box with a Cancel button (and maybe a progress bar or some other activity indicator).

That way the user can't interact with the underlying UI and they still get feedback that something is happening...and the ability to cancel it.

Justin Niessner
sry I should have clarified my question, see edit
mcintyre321
A: 

I can't think of easy way other than disabling all controls except for "cancel".

Having said that, it might give a better user experienced if you displayed a "working" or progress dialog with just a cancel button.

You could use this dailog to display useful information about the progress of the web requests and any error messages that might come back.

ChrisF
+1  A: 

One way would be to put a translucent canvas over the parts of the UI which are not accessible while waiting for the response and in the center put a message with a cancel button.

Doug Ferguson
the cancel button is already visible before the request starts, but I guess we could give it a higher z-index
mcintyre321
It is possible to have more than one button bound to the same command.
Doug Ferguson
sure - I was just thinking about how to do it without creating two identical cancel buttons with one sitting on top of the other
mcintyre321
+1  A: 

Your clickable controls should be bound to commands, and the commands should have CanBeExecuted return false when a background task is in progress. If you do this, the controls bound to those commands will automatically disable and enable themselves.

You can avoid duplicating a lot of code by creating a command class that implements the background-task-in-progress check, and then deriving all of your commands (except the cancel command, of course) from this class.

Robert Rossney
+1  A: 

The Silverlight Toolkit has a BusyIndicator control. The toolkit is open source so you might easily be able to port it to WPF.

It disables and greys out everything in the area that it's assigned to when setting its IsBusy property to true either in code or by binding it to a model. Usage is as follows:

<ctl:BusyIndicator>
    <StackPanel x:Name="myDataArea">
        <Button Content="Load Data" />
        <DataGrid x:Name="myDataGrid" />
    </StackPanel>
</ctl:BusyIndicator>
herzmeister der welten