Tag Archives: Silverlight

Introducing the Prism Navigation Framework for Silverlight MVVM Applications

Another framework? But why?

After receiving a lot of positive feedback and requests for source code for my previous post on Prism navigation i decided to release the code i had as open source project.

This is how Prism Navigation Framework project was born.

My intention was to create simple-to-use but powerful-and-feature-full Navigation Framework for building Silverlight MVVM applications with Prism.

This is the first introductory post (from series of planned similar posts) that will try to explain what this Navigation Framework for Prism can do to make your life as developer easier.

If you are too anxious to read the whole article you can just open the Sample Silverlight Navigation Application Application (for the Beta 1 version of the Framework) and try out some of the features and then read on if you find it to be interesting (in the demo you can see loading Views and their ViewModels to Prism Regions, visual transitions when loading Views, Browser URL and History integration – deep linking, deferred module loading, passing parameters to views etc).

If you are interested in the source of the Prism Navigation Framework and the Sample Application shown here you can download it on the Downloads section on the project site.

Note: Its important to say here that in this post I will not try to explain in detail how Microsoft Patterns and Practices Team Prism works – you must already be familiar with it, and if you never used it to develop Silverlight or WPF MVVM applications, i recommend you to try it out, also make sure to check Prism excellent documentation if you need to refresh your memory.

Basic Concepts

Since Prism Navigation Framework is based on the Prism guidance, naturally it is leaning on and reusing all of Prism main concepts:

  • Modules – packages of application functionality (packaged as .dll or .xap) – they can be loaded immediately on application start or on demand (so called deferred module loading) – this framework completely supports loading of modules implicitly or explicitly.
  • Views and their ViewModels that are packaged in those Modules (each View has its ViewModel set as value of its DataContext property) – this framework allows you to register Views and their ViewModels and then easily load them in many ways, initialize them with parameters etc.
  • Regions - are actually Controls that are used as placeholders on the Views where you can load content – other Views of the application – this framework supports Regions and extends them in practical way – read more below.

One Region To Rule Them All

If you ever built Prism applications you know that by convention each Prism application has one Main View – called the ‘ShellView‘.

Shell View is created on the application start and loaded to represent the main screen of the application.

This main View has multiple Regions – this is where you can load your Views.

Prism Navigation Framework takes Prism’s concept of Regions a little further and defines two types of regions:

  1. Single Main Region – there is only one Main Region in the Application and its usually large region in the center of the Shell View. This Region is meant to be placeholder where we will load other Views – Pages of the Application with the main content. Only one View can be shown in Main Region at one time. This region is represented by dropping instance of PrismNavigationMainFrame control in your ShellView and setting its RegionName.
  2. Multiple Secondary Regions – represented by PrismNavigationSecondaryFrame control – you can place as many of them as you like in the Shell View and load any of application Views into any of those Secondary Regions – Secondary Region can (unlike the Main Region) show multiple Views at the same time (widgets, control etc).

Here is how you would add the single Main Region to your Shell View:

                    <Controls:PrismNavigationMainFrame cal:RegionManager.RegionName="MainRegion" />

And here is how you can add multiple Secondary Regions:

                    <Controls:PrismNavigationSecondaryFrame cal:RegionManager.RegionName="WidgetsRegion" />

                    <Controls:PrismNavigationSecondaryFrame cal:RegionManager.RegionName="OpenedDocumentsRegion" />

Loading Views

We have seen how we can define Main and Secondary Regions so lets see what are our options for loading our Views into those Regions:

  1. First and most useful way to load View into Main region is by typing meaningful URLs in the Browser. Our Framework supports convention over configuration so some defaults work out of the box, for example if you have View control called DetailsView in Module called ProductsModule, then to load this DetailsView into the Main Region of the application just point your browser to this URL:   http://yourapplication.com/index.html#/Products/Details/ (Off course you can pass parameters through the url like this: http://yourapplication.com/index.html#/Products/Details/ProductId/1234  or http://yourapplication.com/index.html#/Products/Details/)
  2. you can also use standard Silverlight HyperlinkButton control and its NavigateUri property to specify URL of the View you want to load (for example “/Products/Details/Id/1″) and its TargetName property to specify to which Region you want View to be loaded
  3. and from your code in ViewModel use the framework’s IPrismViewLoadingService and load Views to any Region in multiple ways: by specifying the View type, or View interface type or just a string name of the View – choice is on you (more on that later). Its important to mention here that when view is loaded via URL – Prism Navigation Framework automatically checks from the URL what is the name of its Module and loads the module if its not already loaded before loading the View, but more on that later.

Modules And How They Relate To Their Views And ViewModels

Now that we covered how to load Views, lets see how the Views and ViewModels are defined, created, registered and initialized in your MVVM application done with Prism Navigation Framework:

Views and ViewModels are in Prism applications packaged in Modules - each module is Silverlight Library (packaged in .dll) or Silverlight Application (packaged in .XAP) that supports some application functionality.

View is usually a UserControl that is just a visual representation of the functionality and its bound to its ViewModel for the data and application logic.

Each module in Prism has to implement IModule interface and it contains InitModule method that is called by the Prism when the Module is loaded.

This is where you need to register your Views and ViewModels so that Prism Navigation Framework can help you instantiate them and load them into Regions.

So here is how your typical Module initialization would look like:

    public class InitModule : IModule
    {
        private readonly IViewRegistrationService _viewRegistrationService;

        public InitModule(IViewRegistrationService viewRegistrationService)
        {
            _viewRegistrationService = viewRegistrationService;
        }

        public void Initialize()
        {
            this._viewRegistrationService.RegisterViewsAndTheirViewModels();
        }
    }

This is possible because each ViewModel needs to inherit the generic type ViewModel<IView> and therefore carries the type (or interface) its View.

This way RegisterViewsAndTheirViewModels method can automagically scan the calling Assembly and look for the types that inherit ViewModel<TView> and registers them for you.

Here is how typical ViewModel definition looks like if you tie your ViewModel to the View interface type:

    public class IndexViewModel : ViewModel<IIndexView>
    {

    }

But off course you can also tie your ViewModel directly to the View type if you want (but i don’t recommend that you do this, tying ViewModel to View interface is much cleaner):

    public class IndexViewModel : ViewModel<IndexView>
    {

    }

Naturally, nothing stops you from manually registering your Views and ViewModels in your Module initialization like this:

    public class InitModule : IModule
    {
        private readonly IViewRegistrationService _viewRegistrationService;

        public InitModule(IViewRegistrationService viewRegistrationService)
        {
            _viewRegistrationService = viewRegistrationService;
        }

        public void Initialize()
        {
            this._viewRegistrationService.RegisterViewAndViewModel<IUserDetailsView, UserDetailsViewModel>();
        }
    }

As long as you use any of these methods of View-ViewModel registrations – your navigation will work.

View Initialization

So now that we know how to register our Views and ViewModels lets see how ViewModel initialization looks like.

Since base class ViewModel implements IAcceptInitializationData interface it is ready to accept initialization data like this:

    public interface IAcceptInitializationData
    {
        void Initialize(ViewInitializationData initializationData);
    }

So whenever some View needs to be shown, behind the scenes its ViewModel will be created, and its Initialize method will be invoked with initialization data (that includes parameters from URLs or directly passed if its done via code) and afterwards this ViewModel will be set as DataContext of the View and then View will be shown in desired prism Region by our Navigation Framework.

Lets take a look at the ViewInitializationData class that is passed to the ViewModel:

    public class ViewInitializationData
    {
        public string Url { get; set; }

        public string RegionName { get; set; }

        public Dictionary<string,string> Parameters = new Dictionary<string, string>();
    }

As you see its enough data for the ViewModel to start functioning – it knows where its loaded – RegionName, how (if via URL then corresponding Url property is filled), and it gets its parameters via Parameters dictionary.
Parameters are parsed from the URL automatically by the framework so you dont have to worry about it.

Can I Show Views From Code in ViewModel?

If you are showing the View from the code, you can pass to it new instance of ViewInitializationData type where you can set your parameters etc.

Also its worth mentioning that if you show some View from code into the Main Region and pass parameters to it, then Browser URL will be updated to show the Url of the View showing the Module name, View name and parameters if any.

For example if you loaded DetalsView from ProductsModule with parameters ProductId = 1234 browser URL would change to something like this: http://yourapplication.com/index.html#/Products/Details/ProductId/1234).

Plumbing

As you can see the Prism Navigation Framework can do a lot of plumbing for you, so that you can focus on the implementation of the application functionality (don’t we all want to do that?).

In order to achieve all this framework is extending the Prism so it needs to call some initialization code in the Bootstrapper class.

To avoid forcing users to manually call that code in every application there is special class PrismNavigationFrameworkUnityBootstrapper that you can use instead of the regular UnityBootstrapper that will do all this initialization for you (for now MEF is not supported by this framework but maybe we will include it later).

So in your application bootstrapper that inherits PrismNavigationFrameworkUnityBootstrapper you don’t need to do anything other than what you would usually do, just create your Shell and register Modules etc, something like this maybe:

    public class Bootstrapper : PrismNavigationFrameworkUnityBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            this.Container.Resolve<IViewRegistrationService>().RegisterViewAndViewModel<ShellView, ShellViewModel>();
            return Container.Resolve<IViewCreationService>().CreateView<ShellView>() as DependencyObject;
        }

        protected override void InitializeShell()
        {
            base.InitializeShell();

            Application.Current.RootVisual = (UIElement)this.Shell;
        }

        protected override Microsoft.Practices.Composite.Modularity.IModuleCatalog CreateModuleCatalog()
        {
            return
                Microsoft.Practices.Composite.Modularity.ModuleCatalog.CreateFromXaml(new Uri(
                    "PrismNavigation.App;component/ModuleCatalog.xaml", UriKind.Relative));
        }
    }

Wrap Up

This is just an introductory post and here you could see only part of what you can expect from this Framework.

I wont go into further details for now, so expect in the future more posts covering every feature of the Prism Navigation Framework in more details.

In the meantime check out the Prism Application Framework Sample Application just to get a feel of what it can do, or browse the latest Source Code or download it and use freely for building your next big Prism Silverlight MVVM application.

Your feedback (both positive and negative) and participation in the development of the project is very welcome!

Combining Silverlight Navigation Framework and Prism to create MVVM Applications – Introduction

This is introductory post for a series of posts where i will try to tackle the holy grail of MVVM applications – Navigation.

To do this I will be using Prism from Microsoft’s Patterns and Practices team (Silverlight version – latest drop) combined with Silverlight Navigation Framework and i will build small navigation framework on top of that.

If you are too busy to read this post and just want to see the result take a look at the current state of the sample Silverlight Prism Navigation application where you can see most of the important features of this small navigation framework (PrismExtensions.dll that contains all the framework code is 35.5 KB in size).

And for those of you with stronger nerves here is the real story:

Lately i have been playing with my old friend Prism and re-discovering how good it is for building MVVM Silverlight and WPF applications.

Out of the box you get a lot of things (and only few months ago i was trying to build all of this from scratch – you can see that from my earlier MVVM blog posts).

One of the things i like the most in Prism is the modularity concept and support for loading application modules dynamically from local/remote servers – on users/application request.

This allows developers to cut the application in modules with isolated functionality and on start load only mandatory parts and then load other modules only if users really needs/request them.

What really surprised me is that nobody has so far managed to combine Prism with Silverlight’s excellent Navigation Framework in a successful way so that is usable for real-life MVVM applications (at least i could not find any good examples on the web).

Prism has a concept of Regions and allows easy loading of Views into them but this is where it ends – there are no higher level concepts of navigation – this is why i decided to build some kind of Navigation framework on top of Prism – to fill that gap.

This is where the very important concept of Deep Linking comes into the story. I cannot imagine any serious Silverlight application without allowing users to bookmark pages in the browser, and to use the Back and Forward browser button to navigate though the UI, to manually ‘hack’ the URLs to load different data etc…

So this is something where Silverlight Navigation Framework can help us. It has built in support for all major browsers for browser history, it notifies the application about the browser URL change, there is HyperlinkButton control that has NavigateUri property where you can specify the application URL that will be loaded when user clicks on it (without full page reload off course – because only the fragment of the URL after # sign is changed) etc.

The only problem is that there is no easy way to combine Prism and Silverlight Navigation Framework.

Yes we can implement INavigationContentLoader and plug it into the Frame control but still we don’t have full control over the page/view loading process, we need additional Frame for each Region where we want to show Views etc.

So i decided to do a little research on how to simplify things and to create a small framework for Prism that will use Silverlight Navigation Framework to load Views into Prism Regions and enable Deep Linking, passing parameters to views, to allow integration with Prism modularity and allow deferred module loading etc – in other words all the features that one would expect to have in modern RIA Silverlight application.

Here are some features that i already support or will in near future:

  • it must be a simple (for the end user-developer) but full blown Navigation Framework for Prism Silverlight MVVM applications
  • it will support this main MVVM scenario: application will have one Main View (so called ‘Shell’) that will be loaded on start of the application and this will be the main ‘screen’ of the application that will have multiple regions where we can load Views. Only one region will be considered as Main Region and it will be ‘tied’ to the URL typed in the browser. Other regions will not update browsers URL or be affected by changes in the URL but application will be able to load Views into other regions – for example Widgets etc (i decided not to support Regions inside Views loaded into Regions on Main Region as this greatly simplifies the implementation and i don’t see a real usage scenario anyway –  instead of using Sub-Regions you can always use child Views inside of your View for that).
  • support for passing the parameters to the Views via browsers URL – every update in the URL of the browser will load appropriate view in Main Region (and pass parameters from URL to the Views ViewModel) and on the other hand, if some View is loaded to Main Region from code, this will reflect on the browser URL (including the parameters passed to View).
  • when View is loaded into region it will be connected to its ViewModel (set as its DataContext) – this is done automagically by the framework, user just needs to define the mapping between Views and View Models in the Module initialization – more details on that in later posts.
  • support for manually loading Views from ViewModels via code (not only via URLs) using the same framework – via some service like IPrismViewLoadingService
  • framework should include support for Prism deferred loading of application Modules – there should be easy way to load Prism Modules that are marked as OnDemand and they should be loaded either manually – from code or automagically – when user navigates to URL that should show View that is in module marked as ‘OnDemand’
  • there should be a way to define User Friendly URL’s – aliases for specific Views and Modules but some smart defaults should work out of the box by default like: “/Products/Detail/1234″  or “/ProductsModule/Details/1234″ etc – user should just type the URL in browser and Framework must load the Module if needed and then show the View (bound to its initialized ViewModel)
  • full support for navigation between Views using HyperlinkButton controls – for loading Views to Main Region and to other Regions
  • framework should be ‘opinionated’ regarding the way how it initializes and binds Views and their ViewModels – in our case it will be View-ViewModel-Marriage approach: there is separate service that initializes ViewModel and set it as DataContext of the View.
  • it should be simple to use for the end user-developer – smart defaults should work without any user configuration yet customization should be possible for advanced scenarios
  • whole solution should be based on services that implement defined interfaces – so that they can be easily changed with different implementations that user could plug via IOC – for example to easily change the parameters format from ‘parameterA/value1/parameterB/value2′ into ‘?parameterA=value1&parameterB/value2′ etc.

So this features should be enough to get us started but we can change this along the way if we see that its appropriate – if you have some suggestions – do let me know!

As you can see from the Sample Application I already have implemented most of these features and I will be finishing along the way as i write more posts in the future – what you can see in the demo right now is: Browser URL history integration (Deep Linking and Back/Forward buttons support), Loading Views with their corresponding ViewModels to Main Region and to secondary Regions, passing parameters to Views, asynchronous deferred loading of Modules/Views etc.

If some you know of some other Prism Navigation Framework that already has most of these features please let me know so i can stop doing this and enjoy real life :)

Otherwise see ya soon in the next part of this article series where i will explain all about this framework and share some code with usage scenarios.

Silverlight MergedDictionaries – using styles and resources from Class Libraries

If you were developing larger Silverlight/WPF applications and trying to keep things like styles, control templates and other resources organized it can become really hard.
Prior to Silverlight 3 it was hell to be honest :D

You had to scatter resources all around your application, on control level and put global ones in App.xaml and soon it would all grow beyond control.

But then nice people from Microsoft introduced lovely little feature called MergedDictionaries that allows you to combine the resources from different places in your application.

The beauty of this simple technique is that you can use resources from different files that can even reside in different Class Libraries in your project and just ‘reference’ them in the application level (App.xaml) and they will immediately become available to all the controls in your application.

Not to mention the moment of reuse: you can group your application resources into assemblies, for example one can hold the Styles, another can contain Control Templates, third can have text resources etc and then you can just reference them in any project and easily (re)use them.

So lets see how to actually accomplish this.
Luckily its very simple. We just need to add few lines to our App.xaml file:

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="ResourceDictionariesInLib.App">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/ResourceDictionariesInLib.BasicStyles;component/StylesForShapes.xaml" />
                <ResourceDictionary Source="/ResourceDictionariesInLib.FontStyles;component/StylesForFonts.xaml" />
                <ResourceDictionary Source="LocalStyles/BasicStyles.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
  </Application.Resources>
</Application>

As you see here I’m using resources from two different Silverlight Class Libraries and one is from local subfolder called “LocalStyles”.
The format is clear, for resources in DLLs you use:
Source=”/AssemblyName;component/FileName.xaml”
The “component” part is just a keyword that tells the parser that resource is in referenced DLL.

One important catch here is if you are merging resources from DLLs than you need to actually add references to those Class Libraries that hold your resources so in this case i had to Add Reference to two DLLs: ResourceDictionariesInLib.BasicStyles.dll and ResourceDictionariesInLib.FontStyles.dll.

Format for the resource file in the application is self-explanatory.

In order to create a xaml file in some Class Library to hold resources just choose Add->New Item and then select SilverlightResourceDictionary from the list.

Also its important to state here that you can put MergedDictionaries at every level, meaning that you can put them to App.xaml and then those merged resources will be available to every element of your application, but also you can place MergedDictionaries in the CustomControl (in CustomControl.Resources) and then this resources will be available only to this control.

So lets see how those MergedDictionaries of resources can be used.

In the StylesForShapes.xaml file i have some background gradient brushes:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <LinearGradientBrush x:Key="EllipseFillBrush" EndPoint="1,0.5" StartPoint="0,0.5">
        <GradientStop Color="Black" Offset="0" />
        <GradientStop Color="#FFD41313" Offset="1" />
    </LinearGradientBrush>

  <LinearGradientBrush x:Key="RectangleFillBrush" EndPoint="1,0.5" StartPoint="0,0.5">
    <GradientStop Color="Black" Offset="0" />
    <GradientStop Color="#FF3AD859" Offset="1" />
  </LinearGradientBrush>

</ResourceDictionary>

So since i referenced StylesForShapes.xaml file in MergedDictionaries in my App.xaml file i can use styles from that file in any Silverlight control in the whole application.

    <Grid x:Name="LayoutRoot" Background="White" Height="348" Width="489">
        <Ellipse Fill="{StaticResource EllipseFillBrush}" />
        <Rectangle Fill="{StaticResource RectangleFillBrush}" />
    </Grid>

You can do the same for any other property like FontSize or FontFamilly.

Just extract property value to a resource and then reuse it in your app.

Another very nice thing about MergedDictionaries is that they are supported by Visual Studio 2010 and Blend 3/4 so if you have DLLs with resources and you merge them in App.xaml then when you are extracting new resources you can specify those resource files in DLL’s as the place where that newly extracted resource will be created.

Here is the example:
In Visual Studio create UserControl and put an Ellipse element on it and set its Fill property to be some nice GradientBrush and then click on the black diamond symbol to the right of the Fill property and in the pop-up menu choose option Extract value to Resource:


After clicking on the Extract Value to Resource menu item you will need to choose where to save the newly created resource and you can here choose any of the resource xaml files in your Class Libraries like this:

So here is how a sample page that uses MergedDictionaries to set styles and fonts on its controls looks like:

And here is the Visual Studio 2010 demo solution.

Have fun! :D

Unit Testing Modal Dialogs in MVVM and Silverlight 4

As feedback to my recent post on Modal Dialogs in MVVM and Silverlight 4 I have received comments that the solution is not easy to Unit Test so i decided to create small blog posts on this subject just to show how simple and clean it is to do this.

So for those who are too lazy to read my original modal dialog post here is a quick reminder:

  • I presented a simple solution how to abstract modal dialogs and message boxes in Silverlight 4 and call them from your ViewModel and act according to the results returned from those modal dialogs.
  • I used Silverlight’s ChildWindow control because it was perfect fit for that job.
  • Important thing is to say that ChildWindow control was used as implementation (with its ViewModel off course) but was hidden by abstractions (like IModalWindow and IModalWindowService) so it can easily be changed by some other implementation and unit tested, mocked out etc.

So in this post i will use the same simple Demo Application for the previous modal dialogs post but I will add few Unit Tests using Silverlight Unit Testing Framework and Silverlight verstion of RhinoMocks.

Our Sample app is very simple and just shows a view with list of some User entities.

Each of users can be edited by clicking on EDIT button next to them – this shows a modal dialog with User editor, we can change details and save them by clicking on OK or CANCEL.

Also there is option to delete each User by clicking on the DEL button – Message Box is shown with OK/Cancel buttons – these are very common scenarios for every LOB application so that’s why i picked them.

I must admit that i improved my framework since the previous post – I changed the signature of the IModalDialogService a little because now in my framework i have a IViewInitializationService that wires up ViewModels with Views so all this is used in this posts just to show it off :)  (more on the IViewInitializationService and the new way how i wire up ViewModels and View in one of the next posts).

So first let’s see the changes made to the IModalDialogView that is the abstraction of the actual modal dialog to be shown:

  public interface IModalWindowView : IView
  {
    bool? DialogResult { get; set; }
    event EventHandler Closed;
    void Show();
    void Close();
  }

So the real ChildWindow that will be our dialog only needs to be marked as implementor of IModalWindowView interface with no additional code needed since this interface contains only methods and properties that ChildWindow already implements:

    public partial class EditUserModalDialogView : IModalWindowView
    {
        public EditUserModalDialogView()
        {
            InitializeComponent();
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }
    }

Also you could see that our IModalDialogView implements our old friend – IView:

    public interface IView
    {
        object FindName(string name);
        object DataContext { get; set; }
        string Name { get; set; }
        event RoutedEventHandler Loaded;
    }

Again nothing to implement here – no code to add – because ChildWindow already implements all this since its inheriting the ContentContol that has all this.

So now lets see the MainPageViewModel for our MainPageView that will actually show the modal dialogs and message boxes:

    public class MainPageViewModel : ViewModel
    {
        private readonly IModalDialogService modalDialogService;
        private readonly IMessageBoxService messageBoxService;
        private ObservableCollection<User> users = new ObservableCollection<User>();

        public MainPageViewModel(IModalDialogService modalDialogService, IMessageBoxService messageBoxService)
        {
          this.modalDialogService = modalDialogService;
          this.messageBoxService = messageBoxService;

          this.Users = new ObservableCollection<User>();

          for (int i = 1; i < 6; i++ )
          {
            this.Users.Add(new User {Username = string.Format("Admin User {0}",
                new Random((int)DateTime.Now.Ticks).Next(10,100)), IsAdmin = true});
            Thread.Sleep(100);
          }

          this.ShowUserCommand =
              new DelegateCommand<User>(userInstanceToEdit =>
                                      {
                                       this.modalDialogService.ShowDialog<EditUserModalDialogViewModel>
                                             (
                                             userInstanceToEdit,
                                             (dialog, returnedViewModelInstance) =>
                                             {
                                                if (dialog.DialogResult.HasValue && dialog.DialogResult.Value)
                                                {
                                                var oldItem = this.Users.FirstOrDefault( u => u.Id == userInstanceToEdit.Id);
                                                var oldPos = this.Users.IndexOf(oldItem);
                                                if (oldPos > -1)
                                                {
                                                    this.Users.RemoveAt(oldPos);
                                                    this.Users.Insert(oldPos, returnedViewModelInstance.User);
                                                }
                                                }
                                            });
                                       });

          this.DeleteUserCommand = new DelegateCommand<User>
              (p =>
                                    {
                                        var result = this.messageBoxService.Show(string.Format(
                                            "Are you sure you want to delete user {0} ???", p.Username),
                                            "Please Confirm", GenericMessageBoxButton.OkCancel);
                                        if (result == GenericMessageBoxResult.Ok)
                                        {
                                        this.Users.Remove(p);
                                        }});

        }

        public ObservableCollection<User> Users
        {
            get { return users; }
            set { users = value;
            this.OnPropertyChanged("Users");
            }
        }

        private ICommand showUserCommand;
        public ICommand ShowUserCommand
        {
            get { return showUserCommand; }
            set { showUserCommand = value;
                this.OnPropertyChanged("ShowUserCommand");
            }
        }

      private ICommand deleteUserCommand;
      public ICommand DeleteUserCommand
      {
        get { return deleteUserCommand; }
        set { deleteUserCommand = value;
        this.OnPropertyChanged("DeleteUserCommand");
        }
      }
    }

As you see ViewModel is simple class and it just has a list of Users to be shown by its View and important things to notice here are two commands for editing and deleting single user.

ShowUserCommand shows modal dialog for editing single user, and DeleteUserCommand just shows MessageBox for confirmation of deletion with OK and Cancel buttons.

So now comes the fun part, lets write unit tests for those commands:

First UnitTest checks that our ShowUserCommand shows the modal dialog for editing the user (using the IModalDialogService). We put expectation on our IModalDialogService mock and invoke our command on ViewModel and verify all expectations afterwards.

Here is the code:

        [TestMethod]
        public void ShowUserCommand_WhenCalledWithSpecificUser_ShowsModalDialogByPassingThatUserAsInitParam()
        {
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            modalDialogService.Expect(
                p => p.ShowDialog<EditUserModalDialogViewModel>(null, null))
                .Constraints(
                Is.Same(userToSend),
                Is.TypeOf(typeof(Action<IModalWindowView, EditUserModalDialogViewModel>)))
                .Repeat.Once();

            viewModel.ShowUserCommand.Execute(userToSend);

            modalDialogService.VerifyAllExpectations();
        }

We first get our ViewModel with Rhino-mocked instances of IModalDialogService and IMessageBoxService and some test Users by calling this methods:

        private static ObservableCollection<User> GenerateSampleUsers()
        {
            return new ObservableCollection<User>()
                                  {
                                      new User() {Username = "user 1"},
                                      new User() {Username = "user 2"},
                                      new User() {Username = "user 3"}
                                  };
        }

        private MainPageViewModel GetInitializedAndMockedViewModel()
        {
            this.modalDialogService = MockRepository.GenerateMock<IModalDialogService>();
            this.messageBoxService = MockRepository.GenerateMock<IMessageBoxService>();
            return new MainPageViewModel(this.modalDialogService, this.messageBoxService);
        }

So that was easy or what?

Lets go to next Unit Test. Lets check that when we call ShowUserCommand with instance of User that when it shows dialog and dialog returns true as its DialogResult – that we replace the original User in ViewModel’s list of Users with the one we got from the modal dialog:

        [TestMethod]
        public void ShowUserCommand_WhenCalledWithSpecificUserAndOnModalDialogResultIsTrue_ShouldReplaceTheOriginalUserInstanceWithOneReturnedFromModel()
        {
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            var dialog = MockRepository.GenerateMock<IModalWindowView>();
            dialog.Expect(p => p.DialogResult).Return(true);

            var mockViewModel = MockRepository.GenerateStub<EditUserModalDialogViewModel>();
            mockViewModel.User = new User() {Username = "mocked"};

            modalDialogService.Expect(
                p => p.ShowDialog<EditUserModalDialogViewModel>(null, null))
                .Constraints(
                    Is.Same(userToSend),
                    Is.TypeOf(typeof (Action<IModalWindowView, EditUserModalDialogViewModel>)))
                .Repeat.Once().WhenCalled(
                    m =>
                        {
                            var action = (m.Arguments[1] as Action<IModalWindowView, EditUserModalDialogViewModel>);
                            if (action != null)
                            {
                                action.Invoke(dialog, mockViewModel);
                            }
                        });

            viewModel.ShowUserCommand.Execute(userToSend);

            Assert.AreEqual("mocked", viewModel.Users[1].Username);
        }

And here is the unit test that checks the DeleteUserCommand so that it actually deletes the user from the ViewModel’s list of users if OK button was clicked on the shown message box:

        [TestMethod]
        public void DeleteUserCommand_WhenCalledWithSpecificUserAndCallToMessageBoxServiceReturnsOk_ShouldDeleteThatUser()
        {
            // arrange
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            this.messageBoxService.Expect(p => p.Show(null, null, GenericMessageBoxButton.OkCancel)).Constraints(
                Is.Anything(), Is.Anything(),
                Is.Anything()).Return(GenericMessageBoxResult.Ok);

            // act
            viewModel.DeleteUserCommand.Execute(userToSend);

            // assert user is not there anymore
            Assert.IsFalse(viewModel.Users.Any( u => u.Username == userToSend.Username));
        }

So it turned out that its quite simple to test Modal Dialogs as long as you have the proper abstractions in place ;)
You can open this page to see all the unit tests running in browser.

Those tests are actually running on the code from the sample demo app!

And as you see all the Unit Tests are green, and the world is safe again :D

Here is the code for all the tests, that is – all 9 of them:

namespace UnitTestingModalDialogs.Tests
{
    [TestClass]
    public class MainPageViewModelTests
    {
        private IModalDialogService modalDialogService;
        private IMessageBoxService messageBoxService;

        private static ObservableCollection<User> GenerateSampleUsers()
        {
            return new ObservableCollection<User>()
                                  {
                                      new User() {Username = "user 1"},
                                      new User() {Username = "user 2"},
                                      new User() {Username = "user 3"}
                                  };
        }

        private MainPageViewModel GetInitializedAndMockedViewModel()
        {
            this.modalDialogService = MockRepository.GenerateMock<IModalDialogService>();
            this.messageBoxService = MockRepository.GenerateMock<IMessageBoxService>();
            return new MainPageViewModel(this.modalDialogService, this.messageBoxService);
        }

        [TestMethod]
        public void ShowUserCommand_WhenCalledWithSpecificUser_ShowsModalDialogByPassingThatUserAsInitParam()
        {
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            modalDialogService.Expect(
                p => p.ShowDialog<EditUserModalDialogViewModel>(null, null))
                .Constraints(
                Is.Same(userToSend),
                Is.TypeOf(typeof(Action<IModalWindowView, EditUserModalDialogViewModel>)))
                .Repeat.Once();

            viewModel.ShowUserCommand.Execute(userToSend);

            modalDialogService.VerifyAllExpectations();
        }

        [TestMethod]
        public void ShowUserCommand_WhenCalledWithSpecificUserAndOnModalDialogResultIsTrue_ShouldReplaceTheOriginalUserInstanceWithOneReturnedFromModel()
        {
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            var dialog = MockRepository.GenerateMock<IModalWindowView>();
            dialog.Expect(p => p.DialogResult).Return(true);

            var mockViewModel = MockRepository.GenerateStub<EditUserModalDialogViewModel>();
            mockViewModel.User = new User() {Username = "mocked"};

            modalDialogService.Expect(
                p => p.ShowDialog<EditUserModalDialogViewModel>(null, null))
                .Constraints(
                    Is.Same(userToSend),
                    Is.TypeOf(typeof (Action<IModalWindowView, EditUserModalDialogViewModel>)))
                .Repeat.Once().WhenCalled(
                    m =>
                        {
                            var action = (m.Arguments[1] as Action<IModalWindowView, EditUserModalDialogViewModel>);
                            if (action != null)
                            {
                                action.Invoke(dialog, mockViewModel);
                            }
                        });

            viewModel.ShowUserCommand.Execute(userToSend);

            Assert.AreEqual("mocked", viewModel.Users[1].Username);
        }

        [TestMethod]
        public void ShowUserCommand_WhenCalledWithSpecificUserAndOnModalDialogResultIsFalse_ShouldNotReplaceTheItemInViewModelWithOneReceivedFromDialog()
        {
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            var dialog = MockRepository.GenerateMock<IModalWindowView>();
            dialog.Expect(p => p.DialogResult).Return(false);

            var mockViewModel = MockRepository.GenerateStub<EditUserModalDialogViewModel>();
            mockViewModel.User = new User() { Username = "mocked" };

            modalDialogService.Expect(
                p => p.ShowDialog<EditUserModalDialogViewModel>(null, null))
                .Constraints(
                    Is.Same(userToSend),
                    Is.TypeOf(typeof(Action<IModalWindowView, EditUserModalDialogViewModel>)))
                .Repeat.Once().WhenCalled(
                    m =>
                    {
                        var action = (m.Arguments[1] as Action<IModalWindowView, EditUserModalDialogViewModel>);
                        if (action != null)
                        {
                            action.Invoke(dialog, mockViewModel);
                        }
                    });

            viewModel.ShowUserCommand.Execute(userToSend);

            Assert.AreNotEqual("mocked", viewModel.Users[1].Username);
        }

        [TestMethod]
        public void ShowUserCommand_WhenCalledWithSpecificUserAndOnModalDialogResultIsNull_ShouldNotReplaceTheItemInViewModelWithOneReceivedFromDialog()
        {
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            var dialog = MockRepository.GenerateMock<IModalWindowView>();
            dialog.Expect(p => p.DialogResult).Return(null);

            var mockViewModel = MockRepository.GenerateStub<EditUserModalDialogViewModel>();
            mockViewModel.User = new User() { Username = "mocked" };

            modalDialogService.Expect(
                p => p.ShowDialog<EditUserModalDialogViewModel>(null, null))
                .Constraints(
                    Is.Same(userToSend),
                    Is.TypeOf(typeof(Action<IModalWindowView, EditUserModalDialogViewModel>)))
                .Repeat.Once().WhenCalled(
                    m =>
                    {
                        var action = (m.Arguments[1] as Action<IModalWindowView, EditUserModalDialogViewModel>);
                        if (action != null)
                        {
                            action.Invoke(dialog, mockViewModel);
                        }
                    });

            viewModel.ShowUserCommand.Execute(userToSend);

            Assert.AreNotEqual("mocked", viewModel.Users[1].Username);
        }

        [TestMethod]
        public void DeleteUserCommand_WhenCalledWithSpecificUser_ShouldCallMessageBoxServiceWithSomeTextThatContainsThatUsersUsername()
        {

            // arrange
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            this.messageBoxService.Expect(p => p.Show(null, null, GenericMessageBoxButton.OkCancel)).Constraints(
                Is.Matching<string>(txt => txt.Contains(userToSend.Username)), Is.Anything(),
                Is.Equal(GenericMessageBoxButton.OkCancel)).Return(GenericMessageBoxResult.Ok);

            // act
            viewModel.DeleteUserCommand.Execute(userToSend);

            // assert
            this.messageBoxService.VerifyAllExpectations();
        }

        [TestMethod]
        public void DeleteUserCommand_WhenCalledWithSpecificUser_ShouldCallMessageBoxServiceWithOkCancelParamForButtons()
        {

            // arrange
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            this.messageBoxService.Expect(p => p.Show(null, null, GenericMessageBoxButton.OkCancel)).Constraints(
                Is.Anything(), Is.Anything(),
                Is.Equal(GenericMessageBoxButton.OkCancel)).Return(GenericMessageBoxResult.Ok);

            // act
            viewModel.DeleteUserCommand.Execute(userToSend);

            // assert
            this.messageBoxService.VerifyAllExpectations();
        }

        [TestMethod]
        public void DeleteUserCommand_WhenCalledWithSpecificUserAndCallToMessageBoxServiceReturnsOk_ShouldDeleteThatUser()
        {
            // arrange
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            this.messageBoxService.Expect(p => p.Show(null, null, GenericMessageBoxButton.OkCancel)).Constraints(
                Is.Anything(), Is.Anything(),
                Is.Anything()).Return(GenericMessageBoxResult.Ok);

            // act
            viewModel.DeleteUserCommand.Execute(userToSend);

            // assert user is not there anymore
            Assert.IsFalse(viewModel.Users.Any( u => u.Username == userToSend.Username));
        }

        [TestMethod]
        public void DeleteUserCommand_WhenCalledWithSpecificUserAndCallToMessageBoxServiceReturnsCancel_ShouldNOTDeleteThatUser()
        {
            // arrange
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            this.messageBoxService.Expect(p => p.Show(null, null, GenericMessageBoxButton.OkCancel)).Constraints(
                Is.Anything(), Is.Anything(),
                Is.Anything()).Return(GenericMessageBoxResult.Cancel);

            // act
            viewModel.DeleteUserCommand.Execute(userToSend);

            // assert user is not there anymore
            Assert.IsTrue(viewModel.Users.Any(u => u.Username == userToSend.Username));
        }

        [TestMethod]
        public void DeleteUserCommand_WhenCalledWithSpecificUserAndCallToMessageBoxServiceReturnsCancel_ShouldNOTDeleteAnyUser()
        {
            // arrange
            var viewModel = GetInitializedAndMockedViewModel();

            viewModel.Users = GenerateSampleUsers();

            var userToSend = viewModel.Users[1];

            this.messageBoxService.Expect(p => p.Show(null, null, GenericMessageBoxButton.OkCancel)).Constraints(
                Is.Anything(), Is.Anything(),
                Is.Anything()).Return(GenericMessageBoxResult.Cancel);

            var usersCountBefore = viewModel.Users.Count;
            // act
            viewModel.DeleteUserCommand.Execute(userToSend);

            // assert user is not there anymore
            Assert.AreEqual(usersCountBefore, viewModel.Users.Count);
        }

    }
}

If you want to investigate further download the Visual Studio 2010 solution and play with it – feel free to use the code as you wish and remember to have fun!