简体   繁体   中英

C# WPF MVVM Window OnLoad Binding

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..

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.

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.

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. Eg 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, eg 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.

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..

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM