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

  • 相关阅读:
    NOI2018 退役记
    APIO2018 被屠记
    CTSC2018 被屠记
    SNOI2018 退役记
    O(1) long long a*b%p
    prufer编码
    杜教筛
    GCC卡常
    NOIP2017滚粗记
    UVA 10763 Foreign Exchange
  • 原文地址:https://www.cnblogs.com/chucklu/p/16594324.html
Copyright © 2020-2023  润新知