4

My Code behind looks like this...

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainWindowViewModel();
    }
}

My ViewModel looks like this...

class MainWindowViewModel : INotifyPropertyChanged
{
    public MainWindowViewModel()
    {
        bool flag = Application.Current.MainWindow.IsInitialized;

        if (flag)
        {
            // Do something...
        }

    }

I guess my question is....Does this conform to the MVVM design pattern? The only other way to do this is How to fire a Command when a window is loaded in wpf

I don't know why, but I don't want to use mvvm-light or any other boilerplate code..

Community
  • 1
  • 1
David Russell
  • 89
  • 1
  • 8
  • All fine. Don't worry :) – dev hedgehog Dec 19 '13 at 19:43
  • 5
    The link you posted doesn't use MVVM Light - using System.Windows.Interactivity is something you'll eventually want if you're doing MVVM - it solves many of these problems. – Reed Copsey Dec 19 '13 at 19:49
  • 1
    If you're going to use Blend, then @ReedCopsey has given good advice. Also look into the `CompositePresentationEvent` classes found in Prism/MEF or similar things which broker app-level messages. You can use them without resorting to the full Prism paradigm. – Rob Perkins Dec 19 '13 at 20:55
  • @RobPerkins I'd recommend using `System.Windows.Interactivity.dll` even if you're not using Blend :) It's full of useful tools for MVVM (behaviors, etc) – Reed Copsey Dec 19 '13 at 21:22

5 Answers5

4

Accessing UI component from ViewModel is violation of MVVM pattern.

Application.Current.MainWindow.IsInitialized is breaking that pattern.

Custom behaviours is more in accordance with MVVM. So, i would suggest to go with the approach you mentioned as link in your question.


Accessing UI component breaks the testability of your ViewModel. How would you write testcase for your ViewModel class? Application.Current will be null when you try to test it via unit test and it will throw null reference exception.

One of the main motive of MVVM was to seperate UI logic from business logic so that business logic can be tested separately without worrying about its consumer which is view.

Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
1

There is no "pure" way to do this in MVVM without boilerplate code. In general, you shouldn't need to do work in response to the VIew within your VM - just the concept is a violation of MVVM, since your ViewModel is trying to do something in response the View, and things should always flow the other way.

The ViewModel shouldn't, in a real scenario, care about the View's state at all - it should be doing nothing but presenting data for data binding by the View.

Most of the time when people are attempting this, it's to try to avoid loading data up front. This is something that's typically handled better by pushing the data to load and starting it directly on a background thread within the ViewModel, then updating the property within the VM when it completes. C# 5's async/await language features can be used to simplify this quite a bit.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • I appreciate everyone's input on this one. MVVM is only a design pattern, but it sure wish it was more considering it's extensive use in business applications. I've got no problem with binding data, using INotifyPropertyChanged and ICommand, but things like this have so much room for interpretation... – David Russell Dec 19 '13 at 20:05
  • 1
    @DavidRussell At the end of the day, just about everybody agrees on the fact that the VM shouldn't know anything about the View - ie: http://reedcopsey.com/blog/wp-content/uploads/2010/01/MVVM.png How you plumb together the rest depends, and different frameworks all have their own ideas about it. Once you know the basics, a framework really does help tremendously (even if you write your own), but things like `EventToCommand`, behaviors, and other event triggers are critical for "real" applications to not violate MVVM – Reed Copsey Dec 19 '13 at 20:39
1

While it is generally believed that having some load/unload logic is a pattern violation, there is a set of use cases, where it's necessary. E.g. a view model may need to be subscribe to some events. If it didn't unsubscribe when unloaded, it might not be garbage collected, depending on the nature of the subscription.

What would break the pattern is accessing view state from within the view model, e.g. manipulating controls. The role of the view model is to expose data to the view and managing load/unload behaviour is part of this contract. Knowing when a view model is loaded means knowing when to expose that data.

While it is true the view model should not care about state of the view, it must know how to prepare data for presentation in the view. More importantly the view model is a layer between the model and the view that makes them separate. Yet in other words: since 'model' means logic, then 'view model' means logic of getting data to display. And it is also about knowing when to fetch it/make it available/etc.

You may want to take a look at this blog post, which provides a convenient way of making a view model aware of being loaded. It is not 100% correct in terms of MVVM purity, because it passes FrameworkElement back into the view model, but imagine we ignore this parameter.

The sample code below is based on the above blog post, but with purer signatures. You could implement IViewModel interface on your classes:

public interface IViewModel : INotifyPropertyChanged
{
    void Load();
    void Unload();
}

Then instruct the view to call adequate methods when loaded or unloaded by using an attached property:

ViewModelBehavior.LoadUnload="True"

Notice the last line has its place in XAML - the view is the one that enforces a certain behaviour, not vice-versa.

pbalaga
  • 2,018
  • 1
  • 21
  • 33
0

What you are currently doing is correct and that is how it is really done with other frameworks behind the scenes.

Since you mentioned MVVM-Light, I suggest you can take a look at caliburn micro. It has very nice framework to conform the MVVM Pattern. Caliburn micro makes it easy to hook up bindings with events on the controls. Just check out its documentation and it is still considered as MVVMy..

123 456 789 0
  • 10,565
  • 4
  • 43
  • 72
  • I'm still relatively new to MVVM. It's too bad everyone teaches WPF using the code behind, but in reality should only be taught using mvvm. This is basically my cheat for triggering something on window load. – David Russell Dec 19 '13 at 19:42
  • Maybe I'm trying to be a purest, but I don't like any 3rd party frameworks in my code if it can help it. I will play around with Caliburn Micro...see if it can convert me...Thanks – David Russell Dec 19 '13 at 19:46
  • 1
    @DavidRussell As for "teaching WPF" - you might want to look at my series on it http://reedcopsey.com/series/windows-forms-to-mvvm/ – Reed Copsey Dec 19 '13 at 19:47
  • 1
    I disagree with your statement that this is "correct" - it's really a direct MVVM violation to do it this way... – Reed Copsey Dec 19 '13 at 19:48
  • @ReedCopsey the first source code was what I meant that it was correct not the second one. I totally disagree that you are accessing Application.Current from the ViewModel. – 123 456 789 0 Dec 19 '13 at 19:58
0

in particular because MVVM is mainly used to guarantee easy to maintain and testable code, you should bear in mind that Application.Current will be null if you use the MainViewModel in UnitTests. Therefore this code will end in a NullPointerException in your tests.

You should consider using the Initialized event if you want to ensure that something is initialized already. But you create the ViewModel after you called InitializeComponent - I simply would leave the check out.

Herm
  • 2,956
  • 19
  • 32