Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prism2/MVVM Close View from ViewModel

Tags:

mvvm

wpf

prism

How do I close a View from its ViewModel?

I've a WPF window which has defined multiple Regions and being used as a Shell to host views for my application. I would like to have a View able to remove itself from the Region, or close it from a tabbed container. How can I accomplish this behavior from ViewModel.

like image 420
Raj Avatar asked Sep 13 '09 06:09

Raj


3 Answers

Since your ViewModel doesn't (and shouldn't) have a reference to the View, you can't close it directly. However, what you can do is add an Event in your ViewModel to indicate that it wants to be closed.

Josh Smith has written an article showing how to do this (about halfway through the article).

like image 53
Julien Poulin Avatar answered Nov 02 '22 23:11

Julien Poulin


This really depends on your app architecture, but here's how I do it with Prism.

First I want to say, it is ok to have your VM reference the View just as long as it is not a concrete implementation of the View, ie, references by interface.

I marry the View and ViewModel using dependency injection, very similar to how it's done in the StockTraderRI. So I have an IView and an IViewModel. IViewModel has a propery called "View" of type IView.

From the code layer (for me, usually the controller...see StockTraderRI) that works with your regions, add the mechanism to remove your view from the region.

For example:

myRegion.Remove(myIViewModel.View);

If regions are handled by a controller, you may want to put a simple event on the VM to notify when a VM wants to be "closed". You can also experiment with the IEventAggregator if you wish to use a weak eventing model. If the region is handled in the VM, simply add that code there.

like image 25
Jeremiah Morrill Avatar answered Nov 03 '22 00:11

Jeremiah Morrill


This how my Login module looks like:

    public class LoginModule : IModule
{
    private readonly IUnityContainer container;

    public LoginModule(IUnityContainer container)
    {
        this.container = container;
    }

    #region IModule Members

    public void Initialize()
    {
        this.container.RegisterType<ILoginController, LoginController>(new ContainerControlledLifetimeManager());
        this.container.RegisterType<ILoginView, LoginView>();
        this.container.RegisterType<ILoginViewModel, LoginViewModel>();

        ILoginController controller = this.container.Resolve<ILoginController>();
        controller.Run();
    }

    #endregion
}

This is the controller:

    public class LoginController : ILoginController
{
    private readonly IRegionManager regionManager;
    private readonly ILoginViewModel model;

    public LoginController(IRegionManager regionManager, ILoginViewModel model)
    {
        this.regionManager = regionManager;
        this.model = model;
        model.RequestClose += new EventHandler(model_RequestClose);
    }

    void model_RequestClose(object sender, EventArgs e)
    {
        regionManager.Regions["LoginRegion"].Remove(model.View);
    }

    #region ILoginController Members

    public void Run()
    {
        // Register views here
        regionManager.Regions["LoginRegion"].Add(model.view);
    }

    #endregion
}

And this is my ViewModel:

    public class LoginViewModel : ViewModelBase, ILoginViewModel
{
    IEventAggregator _eventAggregator;
    RelayCommand _loginCommand;
    private readonly UserProfileRepository _userProfileRepository;
    public event EventHandler RequestClose;

    public ICommand LoginCommand
    {
        get
        {
            if (_loginCommand == null)
            {
                _loginCommand = new RelayCommand(
                    param => this.Login(),
                    param => this.IsValid());
            }
            return _loginCommand;
        }
    }

    public LoginViewModel(IEventAggregator eventAggregator, UserProfileRepository userProfileRepository, ILoginView view)
    {
        this._eventAggregator = eventAggregator;
        this._userProfileRepository = userProfileRepository;
        this.View = view;
    }

    #region ILoginViewModel Members

    public ILoginView View { get; private set; }

    #endregion
}
like image 25
Raj Avatar answered Nov 03 '22 01:11

Raj