开发者

WPF composite Windows and ViewModels

I have a WPF Window which contains few UserControls, those controls contain another. And now, what is the most principal way how to create ViewModel for this Window and wher开发者_运维问答e to bind it.

I do expect that one firstly needs to create ViewModel for each of sub-controls.


There are a few ways to do this.

Inject the VM

I would recommend this method.

If your window is created in the App class like

var window = new MyWindow();
window.Show();

I would assign the VM before showing the window:

var window = new MyWindow();
window.DataContext = GetDataContextForWindow();
window.Show();

If one of your controls needs an own view model assign the VM wile creating the control instance.

DataBind

If you want to set the VM of a control you can bind the DataContext property to an VM instance provided by the surrounding VM.

<Controls:MyControl DataContext={Binding MyControlsVm} />

Code Behind

You may set the VM using the init method in code behind like

public MyWindow()
{
    InitializeComponent();
    DataContext = CreateViewModel;
}

You may use a trick if you don't want to create a VM for your main page:

public MyWindow()
{
    InitializeComponent();
    DataContext = this;
}

and just use the code behind class as VM.


I see the view as a visual representation of the ViewModel so I like WPF picking the view based on the instance of the ViewModel it wants to render.

I call this the View Locator pattern, I use this method to instantiate my view because I have found it to be very simple to implement.

It basically puts an entry in the ResourceDictionary of your app that tells WPF to use an IValueConverter to look up and instantiate the View when it comes across a ViewModel.

So a working example would be:

In your app.xaml:

<Application x:Class="MyApp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml" >
    <Application.Resources>
        <ResourceDictionary Source="Resources.xaml"/>
    </Application.Resources>
</Application>

In resources.xaml:

<DataTemplate DataType="{x:Type vm:ViewModelBase}">
    <ContentControl Content="{Binding Converter={StaticResource ViewModelConverter}}"/>
</DataTemplate>

Set the DataContext of your startup Window Control e.g.

public MainWindow : Window
{
  InitializeComponent();
  DataContext = new MainViewModel();
}

And you're pretty much done. So if you have a MainViewModel like so:

public class MainViewModel : ViewModelBase
{
  public ChildViewModel1 Child1 {get;set;}
  public ChildViewModel2 Child2 {get;set;}
}

and you have a UserControl that resolves to your MainViewModel like so:

<UserControl x:Class="MainView">
  <StackPanel>
    <ContentPresenter Content="{Binding Child1}"/>
    <ContentPresenter Content="{Binding Child2}"/>
  </StackPanel>
</UserControl>

So your ViewModelConverter will return an instance of the appropriate View without any extra effort on your part.


On the child controls issue, why wouldn't one of the properties of the root view model be an instance of the child view model that you would pass onto the child control? The other option would be a converter that converts the non-view model based property into an instance of the child view model (like an adapter pattern).


You might be interested in the sample applications of the WPF Application Framework (WAF). They show how composite Views and ViewModels can be instantiated and how they interact which each other.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜