Bob.
Bob.

Reputation: 4002

How does a View know what ViewModel to use in WPF?

Can someone explain how the View and ViewModel are connected? I can't find anywhere the xaml or the xaml.cs for the View that references the ViewModel, nor anything in the ViewModel.cs file that references the View, yet they are somehow connected, and binding members from the ViewModel to the View work.

Also, in the constructor of each, there is only the InitializeComponent for the View and a basic constructor for the ViewModel (no declaration/definition of the View).

Thanks!

Upvotes: 28

Views: 32228

Answers (4)

Mike Nakis
Mike Nakis

Reputation: 62110

As others have already shown, there are multiple options. Of course, whenever you hear of multiple options you have to wonder what are the advantages and disadvantages of each. Well, it just so turns out that all of them have major disadvantages except one.

The following approach involves no external libraries, no additional housekeeping classes and interfaces, almost no magic, and is very flexible because you can have viewmodels that contain other viewmodels, and you get to instantiate each one of them, so you can pass constructor parameters to them.

For the viewmodel of the main window:

using Wpf = System.Windows;

public partial class TestApp : Wpf.Application
{
    protected override void OnStartup( Wpf.StartupEventArgs e )
    {
        base.OnStartup( e );
        MainWindow = new MainView();
        MainWindow.DataContext = new MainViewModel( e.Args );
        MainWindow.Show();
    }
}

For all other viewmodels:

This is in MainViewModel.cs:

using Collections = System.Collections.Generic;

public class MainViewModel
{
    public SomeViewModel SomeViewModel { get; }
    public OtherViewModel OtherViewModel { get; }
    public Collections.IReadOnlyList<string> Arguments { get; }
    
    public MainViewModel( Collections.IReadOnlyList<string> arguments )
    {
        Arguments = arguments;
        SomeViewModel = new SomeViewModel( this );
        OtherViewModel = new OtherViewModel( this );
    }
}

This in MainView.xaml:

[...]
xmlns:local="clr-namespace:the-namespace-of-my-wpf-stuff"
[...]
    <local:SomeView DataContext="{Binding SomeViewModel}" />
    <local:OtherView DataContext="{Binding OtherViewModel}" />
[...]

As you can see, a viewmodel can simply be a member (child) of another viewmodel; in this case SomeViewModel and OtherViewModel are children of MainViewModel. Then, in the XAML file of MainView, you can just instantiate each of the child views and specify their DataContext by Binding to the corresponding child viewmodels.

Upvotes: 1

Danny Varod
Danny Varod

Reputation: 18118

A "clean" way for connecting the views to the view-models would be...

When you create the views, for each view, set its DataSource to its view-model:

E.g.

public class App
{
    private void OnAppStart()
    {
        var model = new MainModel();
        var vm = new MainVM();
        var view = new MainWindow();

        vm.Model = model;
        view.DataSource = vm;

        view.Show();
    }
}

When the model you are viewing changes, update the VM:

public class MainVM
{
    private void OnSelectedModelItemChanged()
    {
        this.SelectedItem = new ItemVM();
        this.SelectedItem.Model = this.SelectedModelItem;
    }
}

And use data templates to make view select the correct sub views for each VM.

Upvotes: 6

Reed Copsey
Reed Copsey

Reputation: 564771

There are various options here.

Something has to set the View's DataContext to be an instance of the ViewModel. There are lots of options here:

  • This can be done directly in xaml (the View just instances the ViewModel directly).
  • This can be done in the View's constructor (this.DataContext = new MyViewModel();)
  • This can be handled via a DataTemplate
  • A "coordinating" class can wire these together (ie: a separate "presenter" class can construct both and set the DataContext appropriately)

The most common are to either have the View define the VM in the xaml (View-first), or to have everything based from a ViewModel-centric point of view, and have WPF automatically create the View based on the bound VM (ViewModel-first).

The former approach is what's used by a lot of toolkits, such as MVVM Light. The latter approach is what I used in my MVVM blog series, and used by some other toolkits.

Upvotes: 39

Justin
Justin

Reputation: 6559

The view contains an object of the view model class in the xaml.

The InitializeComponent function creates all the controls on the page, sets styles, etc.

Upvotes: 2

Related Questions