如何将DataContext绑定到XAML中的通用ViewModel?

时间:2015-07-30 16:46:17

标签: c# wpf xaml generics mvvm

假设我们有一个像这样的通用View模型:

public class MyViewModel<T> : INotifyPropertyChanged where T : Class1
{
    private T _objectModel;
    public MyViewModel(T object)
    {
        _objectModel= object;
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

当我想将此视图模型绑定到DataContextUserControl的{​​{1}}时,我不能! XAML编辑器找不到My View Model类。我应该如何在XAML中引用泛型类型?

XAML

在上面的代码中,<UserControl.DataContext> <s:MyViewModel<T>/> // How should I write this here???? </UserControl.DataContext> 是我的工作区的别名,如果我将我的通用视图模型转换为具体的类,它可以正常工作。

4 个答案:

答案 0 :(得分:6)

使用XAML时,无法在XAML代码中使用泛型参数实例化视图模型。

要解决此问题,您需要使用继承,这是一个示例:

public abstract class ViewModel<T>

用法:

public class MovieViewModel : ViewModel<Movie>

...

public class GenreViewModel : ViewModel<Genre>

为每个模型创建一个新类似乎有点愚蠢,但这根本不是真的。通过假设每个视图模型包含一个模型,您几乎已经为在所有视图模型中遵循此模式做好准备,因为您的基本视图模型强制执行此约束。

我个人使用ViewModel<T>基类的模式,其中T是模型。

将逻辑与基本视图模型分开当然是个好主意。事实上,每个模型的视图模型都是一个非常好的模式。

还有另一种方法可以实现您所追求的目标,这只是从视图模型库中删除泛型,请考虑以下示例:

public class ViewModel
{
    public object Model { get; protected set; }
}

现在,如果您使用Model填充Movie,则XAML会将其视为Movie,而不是object。现在,就你的XAML方面而言,这是非常好的,但是,当你在 C#中开始使用这个模型时,你将会遇到各种各样的问题,因为你需要施放您正在使用的任何类型的对象。所以我根本不会推荐这个。

解决这个问题的另一种方法是在代码隐藏中设置DataContext,如果你要这样做,那么,只有上帝现在可以救你。围绕MVVM设计模式的主要思想是View逻辑和业务层(View Models)的分离,一旦View开始实例化视图模型,那么很好的分离就会丢失。

现在这样说,没有什么可以阻止你做这件事,我之前已多次这样说了。 MVVM是一种设计模式,不是法律,如果你想在代码隐藏中设置DataContext,那么公平,但重要的是你要意识到其含义。

答案 1 :(得分:4)

您可以创建一个继承自通用ViewModel并使用该

的类
public class PersonViewModel : ViewModel<Person>

XAML:

<UserControl.DataContext>
    <s:PersonViewModel/>
</UserControl.DataContext>

答案 2 :(得分:2)

您无法在XAML中设置通用视图模型,因为XAML在编译时需要已知类型。

依赖注入是你最好的选择

public class MyControl : UserControl{     
   public MyControl(Object viewModel){    
      this.DataContext = viewModel;
   }
}

答案 3 :(得分:1)

如果您的ViewModel是从基类派生的,那么让我们说NonGenericViewModel然后您可以在代码中将NonGenericViewModel类型的对象分配给DataContext。使用这种方式你仍然可以获得泛型的好处,数据绑定也可以工作,因为绑定将在运行时进行,无论你分配给DataContext的对象是什么类型,只要它具有xaml所需的属性,集合等。控制。

BaseViewModel<T> : NonGenericViewModel { ... }

NonGenericViewModel : INotifyPropertyChanged { ... }

在后面的代码中,在你的xaml.cs的代码中:

NonGenericViewModel nonGenVM = new BaseViewModel<person>();
this.DataContext = nonGenVM;

即使这是正确的,也是有效的:

this.DataContext = new BaseViewModel<Person>();

这取决于你是否需要在其他地方使用NonGenericViewModel类。