How to close a View from a ViewModel ?

Note: I wrote this article to clarify relationships between ViewModel and View classes. If you want a complete solution you should take a look at existing MVVM framework like Cinch (by Sacha Barber).

Yesterday, there was an insteresting question about MVVM on StackOverflow: “How to close a View from a ViewModel ?”

Like always with WPF, there are many approaches to solve this problem.

Solution 1: give a reference to the View in the ViewModel

You need to control the View from the ViewModel ? Just gives a reference to the View in the ViewModel constructor.

public Window1()
{
  this.DataContext = new Window1ViewModel(this);
}

Unfortunatelly, this approach has several drawbacks:

  • it breaks the foundamental principle of the MVVM methodology: the ViewModel should be an abstraction of the View
  • it complicates the work needed to unit test your ViewModel
  • it introduces high coupling between the ViewModel and the View

Solution 2: the ViewModel raises an event when it wants to close its associated View

If having a reference to the View in the ViewModel is not the right thing, why not using an event. We can add a RequestClose event in the ViewModel class and raise this event when the ViewModel wants to close its associated View.

The View, when it creates the ViewModel subscribe to the RequestClose event. In the event handler, the View is closed.

// class is omitted, only constructor is shown
public Window1()
{
  var viewmodel = new Window1ViewModel();
  viewmodel.RequestClose += (s, e) => this.Close();

  this.DataContext = viewmodel;
}

Solution 2, first refinement

Of course I prefer the event based solution, but we can improve it. The first refinement we can do is to make sure the event will be coherent over all our classes. To achieve this I setup an interface:

public interface IRequestCloseViewModel
{
  event EventHandler RequestClose
}

This interface is implemented by my ViewModel classes which wants to support the ability to close their associated Views.

Solution 3, second refinement

Another possible refinement is to automate the subscription of the RequestClose event in the View. To do that, I created an abstract ApplicationWindowBase class that inherits from Window. When the DataContext changes, I check if the IRequestCloseViewModel is supported by the DataContext:

public class ApplicationWindowBase : Window
{
  public ApplicationWindowBase()
  {
    this.DataContextChanged += new DependencyPropertyChangedEventHandler(this.OnDataContextChanged);
  }

  private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
  {
    if (e.NewValue is IRequestCloseViewModel)
    {
      // if the new datacontext supports the IRequestCloseViewModel we can use
      // the event to be notified when the associated viewmodel wants to close
      // the window
      ((IRequestCloseViewModel)e.NewValue).RequestClose += (s, e) => this.Close();
    }
  }
}

Like I said in the intro, this a very basic implementation of this concept. Many other approach exists. A good source of information is in the source code of existing MVVM frameworks.

19 thoughts on “How to close a View from a ViewModel ?

  1. I think you’ll still need, in the Execute handler of the command (in the ViewModel) a way to close its associated View.

    Or you have another trick 🙂 ?

  2. Nice idea ! A possible improvement would be to create an attached property, maybe something like “CloseOnRequest”, to automatically handle the RequestClose event and close the Window. That way you would avoid writing code-behind in the View… It should be pretty straightforward, the only difficulty I can think of is that you have to maintain a mapping of which window is bound to which ViewModel, so that you know which window to close

  3. Well, I use a somewhat different pattern that I call PMVP (Presentation Model-View-Presenter), so my suggestion may not be appropriate for MVVM. You can think of PMVP as MVVM with the ViewModel broken up into two separate entities: a Presentation Model encapsulating the data model, UI state information, change notification, and commands; and a Presenter, containing the UI logic (a sort of controller for the view).

    My Presenter classes generally have Run() and Terminate() methods, which (among other things) call OnCreated and OnDestroyed methods on the View. In this pattern, the CloseCommand in the PM would be handled by the Presenter, which would either terminate itself or raise a termination request event to some higher-level entity like an application controller, task director, etc.

  4. Thomas,

    Yes, as always an attached property can always comes to the rescue to clean up our code 🙂

    Mike,

    Ok now it makes sense. Thanks for your details !

  5. Thanks for this useful post!
    But how would you handle closing of a window when user clicks the default window’s Close button? (“Red X”)

  6. I think you could use a Behavior that execute a command whenever a Window is closing. In the command target you could use some kind of “DialogService” to find a service which would open the dialogbox for you 🙂

  7. This doesnt really help though when the VM is behind a user control somewhere down the visual tree, which is more likely. How would you get the event fired from this VM to bubble up to the window that contains the usercontrol which has this Vm as its datacontext?

  8. Rob,

    As I said at the end of the post, this is a very basic implementation. If you need more sophisticated features you would have a dedicated service to manage lifetime of Window. You can take a look at the Calcium framework.

  9. I like this approach, as WPF+MVVM combo matures we will see evolved implementations. But it makes sense to keep things simple in the interim. This is a very simple and reliable solution.

  10. Hi,

    I have a very basic question. (I am new to WPF.)

    In your solution 2, how could you raise event “RequestClose” from ViewModel? I use RequestClose.Invoke(this, new EventArgs()) but the view.close doesn’t seem to be triggered.

    Thanks a lot!

  11. Could you publish a translation of this code in vb.net code?…. the translator utility does not work so well

  12. Hi Antonio,

    I don’t have time to write a VB translation as I’m not familiar with VB at all 🙂
    Sorry I can’t help more

  13. I had a problem using the anonymous method for the close handler.

    I changed the code to what I have below where I unregister the event handler. This takes care of the problem when if you revisit this window the event system will call close on every previous instance of the window. It also prevents a memory leak.


    private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
    if (e.NewValue is IRequestCloseViewModel)
    {
    // if the new datacontext supports the IRequestCloseViewModel we can use
    // the event to be notified when the associated viewmodel wants to close
    // the window
    ((IRequestCloseViewModel)e.NewValue).RequestClose += this.HandleClose;
    }
    }

    void HandleClose(object sender, EventArgs e)
    {
    ((IRequestCloseViewModel)this.DataContext).RequestClose -= this.HandleClose;
    this.Close();
    }

  14. HI Mike,

    Thanks for sharing this tip ! You’re 100% correct about the leak in the original implementation 🙂

    Jeremy

Leave a Reply

Your email address will not be published. Required fields are marked *