locked
Open and close windows in MVVM? RRS feed

  • Question

  • Hi,

    I have read a few posts about this subject, but there seem to not be a definitive answer.

    I have heard people suggest to make a WindowFactory. Why does MVVM make the simplest things complicated?

    What do you believe to be the most elegant way?

    Tuesday, January 12, 2016 7:18 PM

Answers

All replies

  • You could make the window implement and interface and inject the view model with it:

    public interface IView
    {
     void Close();
    }

    ViewModel:

    public ViewModel(IView view)
    {
    ...
    
    public void Close()
    {
    view.Close();
    }
    
    }
    


    View:

    public partial class MainWindow : Window, IView
        {
      public MainWindow()
            {
                InitializeComponent();
         this.DataContext = new ViewModel(this);
     }
    }


    The view model only knows about an interface.

    Or you could send an "open window" or "close window" message from the view model class to some service or controller class or to a view itself that opens a window by calling its Show() method: 
    https://social.msdn.microsoft.com/Forums/vstudio/en-US/637c0b5d-5e1d-48f2-a329-63c233e1451f/launching-a-new-window-from-a-viewmodel-on-a-button-click-in-mvvm?forum=wpf
    http://stackoverflow.com/questions/5829413/wpf-mvvm-how-to-show-a-view-from-mainwindowviewmodel-upon-clicking-on-button

    Or you could use an attached property as suggested in the following thread: http://stackoverflow.com/questions/11945821/implementing-close-window-command-with-mvvm. Please read it for even more suggestions.
     

    Pick the solution that you like the most. Just make sure that your view model is testable without any windows. That's the most important part. MVVM is a design pattern and not a rigid set of rules that you must follow at all times.

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    • Proposed as answer by NiceStepUp Wednesday, January 13, 2016 6:24 AM
    • Marked as answer by Tomer Agmon Wednesday, January 13, 2016 6:34 AM
    Tuesday, January 12, 2016 7:37 PM
  • Hi Magnus,

    I am looking for a solution that does not include any third-party tool kits such as MVVMLight or PRISM. These, in my opinion, add a LOT of code that I don't understand.

    Therefore, the solution that includes creating an interface seems the best and least complicated to me. 

    I just want to make sure I understand the solution.

    Which class implements IView?

    If it would be the ViewModel (as I understand from the above example), I would have a problem if I want to open two different windows from the same ViewModel since it can't implement two different versions of IView.Close().

    It would make sense that the View would implement IView but that is essentialy using behind-code, right?

    Thanks a lot Magnus, you're a great help!!


    • Edited by Tomer Agmon Wednesday, January 13, 2016 10:28 AM
    Wednesday, January 13, 2016 10:27 AM
  • MVVM is different, it does make some things tricky but many things easier.

    The issue someone new to wpf faces is that they don't understand either wpf or mvvm so it all seems much harder.

    Rather the idea of frameworks is they provide you code in order to save you writing it yourself.

    So I think your main issue here is you don't understand what's going on rather than extra code being necessary.

    I recommend you use mvvm light.

    PRISM is very complicated, especially for the newbie. Core functionality is inferior to that of mvvmlight.

    .

    I tend to make viewmodels private members of views.

    Like

       <Window.DataContext>
            <local:MainWindowViewModel/>
       </Window.DataContext>

    If you work that way then you'll find the viewmodel properties are available in intellisense and any mock data your viewmodel offers from the parameterless constructor will appear in design mode.

    You can also override that viemodel at design time using the mc:ignorable approach.

     mc:Ignorable="d"
     d:DataContext="{local:some designer viewmodel}"
    

    If you want a simple way of navigating then consider this:

    http://1drv.ms/1NzSGkg

    It does navigation in the view. It's arguably a view responsibility. If you want to retain state of the views then keep a dictionary with type as key and value usercontrol.Note that these are not windows being navigated, the content of a contentcontrol is switched out for a usercontrol.

    That's a single window app.

    Most users want to do one thing at a time really. If you let them open multiple windows at a time they lose the things and end up part way through transactions on several windows.

    You could easily refactor that sample to use windows rather than usercontrols though.

    Instantiate and show rather than substitute the content.

    And if that looks a bit simplistic

    Then this is rather more like a real application:

    https://gallery.technet.microsoft.com/WPF-Entity-Framework-MVVM-78cdc204


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Wednesday, January 13, 2016 11:05 AM
  • Hi Andy,

    As a true beginner in WPF and MVVM, I'd rather not put code that I don't understand even if it is necessery. I'd rather keep it simple, not have a MVVM-perfect application, but atleast I'll write everything by myself and understand everything.

    On to your example project...

    You're telling me I can call regular events (to open windows) and it's still considered MVVM?

    I'm slowly learning the principles that define MVVM, but it is very complicated for me.

    I appreciate your response, but I would still like an answer for my previous question regarding the interface approach.

    Thanks!

    Wednesday, January 13, 2016 12:03 PM
  • Windows already inherit from Window, which has the show and close methods.

    So I don't really see there's much point in the iView, unless you want to mock a view for automated testing.

    I don't, so I would not use that approach.

    But.

    Say you have iView:

    public interface IView
    {
     void Close();
     void Show();
    }
    

    What that allows you to do is inject either a window or a mock, both of which implement iview. That way you could call show or close on something that isn't a Window during testing. That in turn would mean you can run tests fast enough for TDD. IE, to run thousands in a few seconds in the test window of visual studio.

    .

    MVVM separates out concerns.

    You should have no logic you want to automate tests in the view.

    You're not realistically going to test navigation so yes, showing a window or substituting part of a view is arguably a view concern and you can do it with code.

    I often don't - that sample is very basic.

    And of course the second link doesn't work that way.

    .

    Mvvmlight makes it easier to do a number of things.

    The main one is icommand. You will have a LOT of commands in a wpf app and some way of defining a bindable icommand easily is going to make your life easier. Which is why people invented relaycommand and delegatecommand.

    Compare these two:

    http://social.technet.microsoft.com/wiki/contents/articles/31915.wpf-mvvm-step-by-step-1.aspx

    http://social.technet.microsoft.com/wiki/contents/articles/32164.wpf-mvvm-step-by-step-2.aspx

    The other main thing you get is the ability to easily communicate between classes in a decoupled way.That's using messenger:

    http://social.technet.microsoft.com/wiki/contents/articles/26070.communicating-between-classes.aspx

    You will find ( some way down the road ) that messenger is very useful.

    You could reduce dependence on it using routedcommand, but that's kind of tricky.

    https://joshsmithonwpf.wordpress.com/2008/03/18/understanding-routed-commands/

    http://www.codeproject.com/Articles/28093/Using-RoutedCommands-with-a-ViewModel-in-WPF


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Wednesday, January 13, 2016 1:33 PM
  • >>Which class implements IView?

    The window. The window class already contains a Close method so you don't have to implement it:

    public partial class MainWindow : Window, IView
        {
      public MainWindow()
            {
                InitializeComponent();
         this.DataContext = new ViewModel(this);
     }
    }

    The thing is that the view model shouldn't know anything about the window, but it may be injected with any object that implements the IView interface (such as for example the MainWindow). Then it simply calls a method on an interface and is not coupled to the window in any way.

    And in your unit test against the view model class, you could simply mock the IView interface so you don't have to have a window to be able to test the view model. In other words, the view model have no dependency upon the window but it can still communicate with it loosely coupled through an interface.
     
    Hope that helps.

    Please remember to mark helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Wednesday, January 13, 2016 5:47 PM