0

实例化视图模型时遇到问题。

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

我遇到的问题是,当我创建 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;
  }
}

一旦我使用正确的构造函数通过代码创建了我的视图模型来传递参数,视图模型就会再次由视图使用视图模型的默认无参数构造函数创建。

谁能解释为什么会发生这种情况,并阐明如何设置视图模型优先方法以使其正常工作?我很茫然,我整天都在努力。

谢谢,蒂姆

4

1 回答 1

1

如果您从您的文件中删除以下代码段UserControl并按照我剩余的说明进行操作,我相信您将拥有您想要的东西:

删除这个

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

现在,假设您有一个UserControlorWindow绑定到ViewModel您想要在您的UserControlor中表示的 a Window。这样做的方法是ContentControl在你的内部使用 aUserControlWindow与 aDataTemplate中指定的 a结合使用,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(在对象的层次结构中)。因此,可以说我们将属性设置为您的实例,如下所示:ResourceDictionaryViewModelContentContentRegionMainWindowViewModelMyViewModel

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与您Application.Resources的 App.xaml 文件中的内容合并,如下所示:

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

框架将隐式寻找一个DataTemplatefor Data Type MyViewModel。框架将在我们指定的DataTemplatefor中找到它,并看到它应该由用户控件表示。此时框架将呈现用户控件。MyViewModelResourceDictionaryMyViewMyView

为了子孙后代:

视图模型.cs

using System.ComponentModel;

namespace WpfApplication1.ViewModels
{
    public abstract class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected string _title;

        protected string Title
        {
            get
            {
                return _title;
            }
            set
            {
                _title = value;
                OnPropertyChanged(nameof(Title));
            }
        }

        protected void OnPropertyChanged(string propName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        }
    }
}
于 2017-03-07T04:02:26.040 回答