In this post I'll talk about working with dialogs in a MVVM application. The other posts in this series are as follows (I'll update this list as they are published):
- Silverlight, MVVM & SharePoint - About this Series...
- Silverlight, MVVM & SharePoint - How I do MVVM
- Silverlight, MVVM & SharePoint - My favorite MVVM toolkit - MVVM Light Toolkit
- Silverlight, MVVM & SharePoint - Working with Commands
- Silverlight, MVVM & SharePoint - Working with Messages
- Silverlight, MVVM & SharePoint - Working with Dialogs
- Silverlight, MVVM & SharePoint - Testing the Business Logic
- Silverlight, MVVM & SharePoint - Testing the User Interface
- Silverlight, MVVM & SharePoint - Using Data Services
One thing I found tricky at first when learning MVVM was how to handle the case of dialogs. They are a fully UX capability but they also were used for things such as creating and editing items. I needed to find a way to get dialogs to appear but without being triggered from the UI rather from the view model, how to handle their actions and how to make all of that stuff fully testable!
Enter the MVVM Light Toolkit, specifically the Messenger capability I talked about previously in this series. The approach I take with MVVM is that you should strive for zero code in the code behind of the XAML files (aka: zero code in the UI). But how to launch a dialog. Well, is it OK if there is code in the XAML code behind if it is 100% view related but not application related? I think so... so here's how I do it:
- When I want to show a dialog, I broadcast a message from the view model.
- In the code behind for the hosting view (the XAML file), I have the Messenger listen for that message.
- When that message is received, I show the dialog.
- When the dialog closes, if the user clicked OK, I run some code... the code that was defined as an action (aka: the callback) in the message as defined in the view model!
Confused? OK... here's how I broadcast the message (such as when the user clicks the button to show the app settings ). It is a command that broadcasts the message:
The LaunchSettingsDialogMessage is just a subclassed version of the DialogMessage. I could add more properties to it, but I just wanted a named object. Next up, look at the main view's code behind. In the constructor it registers a listener for this message and when it gets it, it launches a dialog:
Now, let's just hypothetically assume that this dialog wanted to go and run some code after the dialog closed. When I created the LaunchSettingsDialogMessage, one of the parameters you pass in is an action, or the code run whenever the receiver wants. Then, the receiver can call the code by calling message.Execute() and that will run the code saved in the message to run.
Best of all, this is fully testable! How? Well when you create the test, YOU create the listener for the message and you listen for it. So for instance, here's a test that verifies the message was broadcast by the command and received by any listeners:
In my next post I'll talk about unit testing a Silverlight application, specifically one that has async calls in it that you need to test and the challenges associated with that. But here you can see how easy it is to test the messages are flowing from another app.