views:

1018

answers:

3

I'm moving along on a small proof of concept application. This is mostly to beef up my MVVM skills within Silverlight. I came across an interesting problem today that I could not figure how to solve the MVVM way. I wasn't successful finding anything relevant during search either.

So on to the problem, I have a simple business type application with a database back end. I have a login view and a view model attached that will perform the login and report success or failure. No problem. What I haven't been happy with just yet is a way to report a wait screen to the user. So given my login screen, the user click Login and there's a delay of a couple of seconds while the database chatting is done. I'd like to report this and disable any interaction until the call is completed.

I had a couple of ideas. First, bind the Cursor property to the viewmodel and the VM can set an IsBusy property to true. Problem with this is that I cannot seem to bind to Cursor for the UserControl (Visual Studio says AG_E_RUNTIME_MANAGED_UNKNOWN_ERROR).

Second idea is to have a wait screen. You know, the little gears turning or whatever animation you want. And that's fine, but it's not real clear to me how I could make the view toggle this through the model through the Xaml. I know I could definitely hook up events and handle this in code. Maybe that's the way to go? Seems to against the MVVM grain just a bit.

Would be interested in more ideas on how to handle this.

Thank you.

A: 

You could use the Mediator prototype that Josh Smith created to have a loosely coupled messaging system from the VM to the V. The VM could push out a message that it is "busy", with the view subscribing to this "IsBusy" message.

The view could then show the correct dialog until a "IsNotBusy" message is received.

Another option is to pass to the ViewModel in the constructor some interface like IDialogProvider that has methods to show a dialog. The implementation of this provider will be view specific but at least the view model only knows about the interface and not a concrete implementation.

public interface IDialogProvider
{
 void ShowErrorMessage(string message);
}

Mediator Prototype

Ray Booysen
Thank you so much for the reply. I read the mediator article a couple of times and I think I get it. But it seems like overkill. I like the IDialogProvider, but I'm fighting with myself about one point, is it really the responsibility of the viewmodel to display UI? If not, why not simply have events for the view to subscribe to and have it display UI accordingly?
billb
If you use the View to bind to events on the VM, why have the VM in the first place. The IDialog provider could be any interface to let the View know that a dialog is required. The ShowErrorMessage could be replaced with anything you see fit.
Ray Booysen
+1  A: 

We've ended up using a service for processing long running requests. The service takes the workload as a delegate, and then passes it off to a BackgroundWorker, while also opening our "Please wait" view.

This works well as it allows us to control long running processes across all our ViewModels in the same way, with a fairly simple interface.

You could have events coming from the ViewModel update the View when you need a delay, but then you need to have this code in all your ViewModels, and not in a single class that can be maintained more easily.

EDIT A service is just a class that's registered within your IOC container, and can be used by your ViewModels.

public interface IProcessingService
{
    void Process(Action<BackgroundWorker> action);
    void Process(Action<BackgroundWorker> action, 
        Action<RunWorkerCompletedEventArgs> finish);
}

Using this your ViewModel could implement something like this.

{
    var processingService = container.Resolve<IProcessingService>();
    processingService.Process(worker => 
    {
        worker.ReportProgress(0, "Please wait...");
        // Do work here
        worker.ReportProgress(50);
        // Do more work
        worker.ReportProgress(100);
    });
}

This way all your code for displaying the progress notification is in the class that implements IProcessingService and your views remain free of any code that directly controls a view or any UI elements.

Cameron MacFarland
Would you mind elaborating just a bit? When you say 'ended up using a service', I don't quite follow. Obviously, I'm using a wcf service to handle the process, SL calls the service asynchornously, are you saying that there's another service that calls the wcf service?I really like the idea of having the 'wait' screen / code in a single place, this is ultimately what I'm after.
billb
A: 

I think others might be "overthinking" this one...

I would recommend using the BusyIndicator in the Silverlight toolkit.

Simple XAML:

<toolkit:BusyIndicator Name="busyBoy" IsBusy="true" BusyContent="Fetching Data..." Margin="6,248,0,0" />
Lucas B