MVVM视图与ViewModel绑定问题

时间:2017-03-07 00:09:32

标签: mvvm data-binding viewmodellocator

我在实例化viewModels时遇到了问题。

我大部分时间都在使用ViewModelLocator,因为在大多数情况下我必须注入依赖项。但是有些情况下我需要将参数传递给ViewModel。据我所知,我需要使用ViweModel-First方法。这意味着我需要为ViewModel创建一个DataTemplate,它在运行时绑定到View。确保包含一个带有我想传入的参数的构造函数。

我遇到的问题是,当我创建ViewModel并传入我的参数时,会调用正确的构造函数。但是因为ViewModel绑定到视图,所以视图调用viewmodel的默认无参数构造函数。

以下是我将ViewModel绑定到的UserControl的XAML:

<UserControl x:Class="MyView">
    <UserControl.DataContext>
      <viewModels:MyViewModel></viewModels:MyViewModel>
    </UserControl.DataContext>
</UserControl>

数据模板如下所示:

<DataTemplate DataType="{x:Type viewModels:MyViewModel}">
   <views:MyView></views:MyView>
</DataTemplate>

以下是ViewModel示例:

public class MyViewModel : ViewModelBase
{
  private MyModel _myModel;

  public MyViewModel()
  {
  }

  public MyViewModel(MyModel myModel)
  {
    _myModel = myModel;
  }
}

一旦我使用正确的构造函数通过代码创建我的viewModel来传递参数,视图将使用viewModel的默认无参数构造函数再次创建viewModel。

任何人都可以解释为什么会发生这种情况并阐明如何设置viewmodel-first方法以使其正常工作?我很茫然,我一整天都在努力。

谢谢, 添

1 个答案:

答案 0 :(得分:1)

如果您从UserControl删除以下代码段并按照我的其余说明操作,我相信您会得到您想要的内容:

删除此

<UserControl.DataContext>
      <viewModels:MyViewModel></viewModels:MyViewModel>
</UserControl.DataContext>

现在,假设您希望在UserControlWindow中代表ViewModelUserControl绑定到Window。这样做的方法是使用ContentControlUserControl内的Window以及DataTemplate中指定的ResourceDictionary,如下所示:

<强> .XAML:

<Window x:Class="WPF_Sandbox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:WpfApplication1.ViewModels"
    Title="MainWindow"
    x:Name="ThisControl">
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    <DockPanel LastChildFill="True">
        <ContentControl DockPanel.Dock="Left" Content="{Binding NavigationRegion}"/>
        <ContentControl DockPanel.Dock="Left" Content="{Binding ContentRegion}"/>
    </DockPanel>    
</Window>

ContentControl将隐式查找与绑定到其DataTemplate属性的ResourceDictionary关联的ViewModel(在Content个对象的层次结构中)。因此,我们假设我们将ContentRegion中的MainWindowViewModel属性设置为MyViewModel的实例,如下所示:

<强> MainWindowViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfApplication1.ViewModels
{
    public class MainWindowViewModel : ViewModel
    {
        private object _navigationRegion;
        private object _contentRegion;

        public object NavigationRegion
        {
            get
            {
                return _navigationRegion;
            }
            set
            {
                _navigationRegion = value;
                OnPropertyChanged(nameof(NavigationRegion));
            }
        }

        public object ContentRegion
        {
            get
            {
                return _contentRegion;
            }
            set
            {
                _contentRegion = value;
                OnPropertyChanged(nameof(ContentRegion));
            }
        }

        public MainWindowViewModel()
        {
            ContentRegion = new MyViewModel(new MyModel());
        }
    }
}

你有ResourceDictionary指定如此:

<强> MyResourceDictionary.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApplication1"
                    xmlns:vm="clr-namespace:WpfApplication1.ViewModels"
                    xmlns:views="clr-namespace:WpfApplication1.Views">
    <DataTemplate DataType="{x:Type vm:MyViewModel}">
        <views:MyView/>
    </DataTemplate>

</ResourceDictionary>

您已将ResourceDictionary与App.xaml文件中的Application.Resources合并,如下所示:

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApplication1"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="MyResourceDictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

框架将隐式地为数据类型DataTemplate寻找MyViewModel。框架将在我们指定的DataTemplate中找到MyViewModel的{​​{1}},并看到它应由ResourceDictionary用户控件表示。此时,框架将呈现MyView用户控件。

为了后人的缘故:

<强> ViewModel.cs

MyView