MVVM - How do I Bind the View Model to the View

MVVM - How do I Bind the View Model to the View

问题

and thanks in advance for the guidance. I'm new to MVVM, and I've been learning via articles. I think I've gotten pretty far, but there's one thing that seems to escape me. How do I (not using code in the code behind) automatically bind to the view I want? As I understand it, if done correctly, this is how the pattern should work. I can make this all happen using code behind in the main window xaml, and I have even created a resource dictionary correctly (as I can access it in the immediate window.) I just can't get to that next step of 'automation.' It could be my design, as I new to this pattern I'm totally amenable to the possibility that I've done this all wrong. Here's what I have...

I have a main window. It's a grid with 3 rows. The top row is a menu. The bottom row is a status bar. The middle is a stack panel where the content is dynamically loaded based on the menu selection.

I have 2 views that I am using to fill this stack panel. One has nothing more than a styled textbox in it (Help & About.) The other is itself a composite view: a search panel, a results grid and a detail panel all loaded into a dock manager frame.

In the main window code behind, when the user clicks a menu option, I clear the children of the stack panel, instantiate the view model, instantiate the view passing the view model into it and then add the new view into the children of the stack. This works fine, but I don't think it's consistent with the pattern.

As I mentioned I have the resource dictionary, but I don't know how to associate it with the stack panel. I assume that I have to use binding, but I can't figure out how to bind to the resource dictionary and/or how to tell it to change views on command.

I have read articles that have added all of the available view models to a read only list in a view model that essentially acts as the go between the main widow and the actual view models needed. This seems OK, but I don't understand why the resource dictionary is needed then. Moreover, these examples were wizard implementations and in that scenario this seems like a good approach, but I can't imagine doing that for an application with say 100 view models.

Again, sorry for my ignorance, but I was hoping that someone could point me in the right direction. As I said, I've read a ton of articles (Josh Smith, Dave Hill, etc.) and I still haven't made the connection, so I was hoping for some concrete guidance. (I do have WPF Unleashed on the way, but I was hoping to make some progress before then.)

Can anyone help?

 

 

回答1

There are ways on how to bind your view models.

1. Create a static resource in the XAML.

这是两个组合起来使用,定义了Window.Resources, 里面的key是MainVM。然后在Grid的DataContext里面绑定

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
  <Window.Resources>
    <local:MainViewModel x:Key="MainVM" />
  </Window.Resources>
  <Grid DataContext="{StaticResource MainVM}">

  </Grid>
</Window>

 

2. Bind in View's constructor

直接在构造函数里面绑定DataContext

I know you mentioned not using code behind but this is also an option. As long as you don't write any logic in the code behind then you're good.

public MainWindow()
{
  InitializeComponent();
  this.DataContext = new MainViewModel(); 
}

 

3. Bind using ViewModelLocator

You might want to create a view model locator class that is in charge of giving your view the viewmodel that it needs.

Here's a simple example of a viewmodel locator class. The viewmodel locator class exposes some viewmodel properties. Then later on we will bind these properties to the data context of the views.

 public class ViewModelLocator
  {
    public ViewModelLocator()
    {
      this.MainVM = new MainViewModel();
      this.AnotherVM = new AnotherViewModel();
    }
    public MainViewModel MainVM { get; set; }
    public AnotherViewModel AnotherVM { get; set; }
  }

Then you can create a static resource of the viewmodel locator in the App.xaml to make it available to all the views within the app.

<Application x:Class="WpfApplication2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApplication2"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
      <local:ViewModelLocator x:Key="Locator" />         
    </Application.Resources>
</Application>

Then you can bind your view's data context to the viewmodel locator's property.

The example tells us that you are binding the MainVM property if the viewmodel locator, which is a MainViewModel instance, to the Window's data context.

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding MainVM, Source={StaticResource Locator}}">

 

回答2

I've not used WPF but I've used Silverlight and I believe it should be pretty much the same.

When I create my View I instantiated the required ViewModel within the View. I use MEF for Dependency Injection and create the Required VM that way, you might not want to go down that route but it could give you an idea.

e.g. ViewModel:

[Export] // This attribute tells MEF to export an instance of this class
public class MyViewModel
{ ... }

View

[Import] // MEF will look for any exported objects of type MyViewModel
public MyViewModel ViewModel
{
  get { return this.DataContext as MyViewModel; }
  set { this.DataContext = value; }
}

This way saves instantiating your VM and your V, just create your V and let that care about instantiating the VM and setting it's own DataContext.

 

作者:Chuck Lu    GitHub    
posted @   ChuckLu  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2021-08-17 游戏术语
2021-08-17 the user account is not authorized for remote login
2020-08-17 乐刻健身房 间隔天数
2015-08-17 Linq打印
2015-08-17 .net framework client profile
2015-08-17 Resharper中注释代码的快捷键
2015-08-17 What does the number on the visual studio solution icon represent?
点击右上角即可分享
微信分享提示