Posted by: Zeeshan Amjad | March 9, 2011

Implement Close Window functionality in ViewModel


When we are creating application using MVVM pattern, it is very important to not include any user interface specific functionality in the ModelView. If we are doing this, then we are not only violating the separation of concern, but also make it difficult to write test cases for our application. But sometimes we are not sure how to implement one functionality without breaking the MVVM pattern. One such concept is to implement the close functionality in model view.

Lets take a look at this example. Here is very our ModelView class that has one property of ICommand type to close the window.

Code Snippet
  1. public class MyViewModel : DependencyObject
  2. {
  3.     public ICommand ExitCommand
  4.     { get; set; }
  5.  
  6.     public MyViewModel()
  7.     {
  8.         ExitCommand = new MyCommand(CloseWindow);
  9.  
  10.     }
  11.  
  12.     private void CloseWindow()
  13.     {
  14.         // do something
  15.     }
  16.  
  17.     // other stuff
  18. }

 

Here MyCommand is simple implement of ICommand interface. Here is its simple implementation.

Code Snippet
  1. public class MyCommand : ICommand
  2. {
  3.     public Action Function
  4.     { get; set; }
  5.  
  6.     public MyCommand()
  7.     {
  8.     }
  9.  
  10.     public MyCommand(Action function)
  11.     {
  12.         Function = function;
  13.     }
  14.  
  15.     public bool CanExecute(object parameter)
  16.     {
  17.         if (Function != null)
  18.         {
  19.             return true;
  20.         }
  21.  
  22.         return false;
  23.     }
  24.  
  25.     public void Execute(object parameter)
  26.     {
  27.         if (Function != null)
  28.         {
  29.             Function();
  30.         }
  31.     }
  32.  
  33.     public event EventHandler CanExecuteChanged
  34.     {
  35.         add { CommandManager.RequerySuggested += value; }
  36.         remove { CommandManager.RequerySuggested -= value; }
  37.     }
  38. }

 

Now the question is what should we write inside the CloseWindow method. There are multiple ways to solve this problem such as pass the reference of the window either at the time of creation of ModelView class or after it and use that reference to close the window. But in that case our ModelView class is no more UI independent.

The other approach it to use the Event rather than reference of window. Our first step is to create a public even in our model view class and let that event handle the CloseWindow command. Here is a simple implementation of this.

Code Snippet
  1. public class MyViewModel : DependencyObject
  2. {
  3.     public event EventHandler RequestClose;
  4.  
  5.     public ICommand ExitCommand
  6.     { get; set; }
  7.  
  8.     public MyViewModel()
  9.     {
  10.         ExitCommand = new MyCommand(CloseWindow);
  11.  
  12.     }
  13.  
  14.     private void CloseWindow()
  15.     {
  16.         EventHandler handler = this.RequestClose;
  17.  
  18.         if (handler != null)
  19.         {
  20.             handler(this, EventArgs.Empty);
  21.         }
  22.     }
  23.  
  24.     // other stuff
  25. }

 

It is not necessary that we create System.EventHandler, but we can use our own delegate too for this purpose. But just to keep simple we are not going to introduce any delegate type here and create event of our newly create event and stick with System.EventHandler.

In this case we simply check if the value of that event handler is not null then let that event handler handle the command. Our model view is still independent of any user interface element. Now the last part is to assign a delegate to this event handler.

There are two ways to assign the event handler in our view class. One approach is to create a handler method of this event and call close method there. Here is a simple code to demonstrate this concept.

Code Snippet
  1. public partial class MainWindow : Window
  2. {
  3.     private MyViewModel vm = new MyViewModel();
  4.  
  5.     public MainWindow()
  6.     {
  7.         InitializeComponent();
  8.  
  9.         vm.RequestClose += new EventHandler(CloseWindow);
  10.         DataContext = vm;
  11.     }
  12.  
  13.     public void CloseWindow(Object source, EventArgs args)
  14.     {
  15.         Close();
  16.     }        
  17. }

 

The other approach is to use anonymous method. We can create unnamed event handler. Here is a code to demonstrate this concept.

Code Snippet
  1. public partial class MainWindow : Window
  2. {
  3.     private MyViewModel vm = new MyViewModel();
  4.  
  5.     public MainWindow()
  6.     {
  7.         InitializeComponent();
  8.  
  9.         EventHandler handle = delegate
  10.         {                
  11.             Close();
  12.         };
  13.  
  14.         vm.RequestClose += handle;
  15.         DataContext = vm;
  16.     }
  17. }

 

Or even lesser code something like this.

Code Snippet
  1. public partial class MainWindow : Window
  2. {
  3.     private MyViewModel vm = new MyViewModel();
  4.  
  5.     public MainWindow()
  6.     {
  7.         InitializeComponent();
  8.  
  9.         vm.RequestClose += delegate
  10.         {
  11.             Close();
  12.         };
  13.  
  14.         DataContext = vm;
  15.     }
  16. }

Advertisements

Responses

  1. […] already saw the implementation of ICommand interface here, here and here. That was very naïve implementation. The biggest problem with this implementation is that we […]

  2. Where is the XAML example code?

    • This is just a utility class can be used with any MVVM application. Thanks for visiting the blog.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: