Open/Close View from ViewModel Open/Close View from ViewModel wpf wpf

Open/Close View from ViewModel


As soon as you refer to UI elements(In this case the View) from the VM, you're going against suggested MVVM Guidelines. With just that we can know creating the Window object in the VM is wrong.

So now onto rectifying this:

  • Firstly try to keep a 1 View <-> 1 VM in your application. It's cleaner and allows you to switch out View implementations with the same logic very easily. Adding multiple View's to the same VM even if not "ground-breaking" just makes it clumsy.
  • So now you got AddClientView and SuggestedAddressesView with their own VM. Great!

Implementing a View Open/Close from the VM:

  • Since we cannot access the View directly from our VM(to comply with standards), we can use approaches such as using a Messenger(MVVM Light), EventAggregator(PRISM) and so on to send a "message" from the VM to the View when you need to open/close a View and do the actual operation in the View.
  • This way the VM just initiates the message and can be unit-tested fine for the same operation and does not reference any UI elements.

Using a "Messenger" approach to handle View open:

  • As per your Logic, it is the AddClientViewModel which would have to ask for the SuggestedAddressesView to be opened.
  • Thus when you detect SuggestedAddresses.Count > 0, you would send a message to the AddClientView asking it to open up the SuggestedAddressesView.
  • In AddClientView.xaml.cs upon receiving this message, you would do what you're currently doing in the VM. Create an object of SuggestedAddressesView and call .Show() on it.
  • One extra step you would add in the above step's process is to assign the DataContext of SuggestedAddressesView as SuggestedAddressesViewModel.

That's it. Now what you have is, when AddClientViewModel wants SuggestedAddressesView shown, it sends a message to it's own View and the View in-turn creates and shows the SuggestedAddressesView. This way the VM does not reference any View's and we keep to holding MVVM standards.

Using a "Messenger" approach to handle View close:

  • Closing a View is pretty simple. Again when you need to close the View from the VM, you send a message to it's own View asking for it to be closed.
  • On receiving this message, the View pretty much closes itself via .Hide() / .Close() or however else you want to get rid of it.

In this each VM handles it's own View's closing and you don't have any inter-connected dependencies.

You can use this as a start point to guide you in handling "messages" for this approach. it has an attached download you can get and see how the Messenger works. This is with MVVM Light, if you do not use it or use something else/ your own MVVM implementation, use it as a guide to help get to what you need.


you can use RelayCommand so that you send the parameter as follows:

Command="{Binding CloseWindowCommand, Mode=OneWay}" CommandParameter="{Binding ElementName=TestWindow}"

By using this you can close the individual views.

Example:

public ICommand CloseCommand    {        get        {            return new RelayCommand(OnClose, IsEnable);        }    }public void OnClose(object param)    {       AddClientView/SuggestedAddressesView Obj = param as AddClientView/SuggestedAddressesView;       obj.Close();    }


To open window from ViewModel:

Create NavigationService.cs class for opening window:Let NavigationService.cs

Now put following code in that class file.

   public void ShowWindow1Screen(Window1ViewModel window1ViewModel)       {           Window1= new Window1();           Window1.DataContext = window1ViewModel;           Window1.Owner = Window1View;           Window1.ShowDialog();       }

then.Create instance of NavigationService.cs class MainWindowViewModel file.Then

Window1ViewModel window1ViewModel = new Vindow1ViewModel();window1ViewModel.Name = MainWindowTextValue;NavigationService navigationService = new NavigationService();navigationService.ShowWindow1Screen(window1ViewModel);