【问题标题】:How Can I bind DataContext to a Generic ViewModel in XAML?如何将 DataContext 绑定到 XAML 中的通用 ViewModel?
【发布时间】:2015-10-22 03:42:17
【问题描述】:

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

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

当我想将此视图模型绑定到 UserControl 中的 DataContext XAML 时,我不能! XAML 编辑器找不到我的视图模型类。我应该如何在 XAML 中引用泛型类型?

<UserControl.DataContext>
    <s:MyViewModel<T>/> // How should I write this here????
</UserControl.DataContext> 

在上面的代码中,s 是我的工作区的别名,如果我将通用视图模型转换为具体的类,它可以正常工作。

【问题讨论】:

  • 据我所知,XAML 没有泛型的概念。
  • 您可能在您绑定到的后台代码中有一个通用视图模型。然后,在您想要的视图模型中构建传递。但要在 XAML 中做到这一点?我不这么认为
  • 感谢您的建议。因为我是WPF 的新手。您能否给我一个链接,例如在后面的代码中绑定DataContext?有什么区别?将 MVVM 方程放在后面的代码中意味着动态绑定。我说的对吗?
  • @AnthonyRussell 哦,谢谢 ;)

标签: c# wpf xaml generics mvvm


【解决方案1】:

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

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

public abstract class ViewModel<T>

用法:

public class MovieViewModel : ViewModel<Movie>

...

public class GenreViewModel : ViewModel<Genre>

为每个模型创建一个新类似乎有点愚蠢,但事实并非如此。通过假设每个视图模型包含一个模型,您几乎已经为在所有视图模型中遵循此模式做好了准备,因为您的基本视图模型强制此约束。

我个人使用ViewModel&lt;T&gt; 基类的模式,其中T 是模型。

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


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

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

现在,如果您使用 Movie 填充 Model,那么 XAML 会将其视为 Movie,而不是 object。现在,就您的 XAML 方面而言,这已经相当不错了,但是,当您开始在 C# 中使用此模型时,您将遇到各种问题,因为您必须进行强制转换对象到您使用的任何类型。所以我完全不推荐这个。


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

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

【讨论】:

    【解决方案2】:

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

    BaseViewModel<T> : NonGenericViewModel { ... }
    
    NonGenericViewModel : INotifyPropertyChanged { ... }
    

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

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

    即使这是正确且有效的:

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

    这取决于您是否需要其他地方的类 NonGenericViewModel。

    【讨论】:

      【解决方案3】:

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

      依赖注入是你最好的选择

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

      【讨论】:

      • 谢谢,但我认为需要MyControl&lt;T&gt; : UserControl 之类的东西!有可能吗?
      • 最好的办法是使用依赖注入
      【解决方案4】:

      您可以创建一个继承自通用 ViewModel 的类并使用它

      public class PersonViewModel : ViewModel<Person>
      

      XAML:

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

      【讨论】:

      • 不,它不会取消泛型的任何优点。您仍然可以为任何模型类型创建 ViewModel,而无需重新编码 ViewModel 功能。
      • 这将在 ViewModel 之上工作更多。我认为直接用 ViewModel 提供视图比创建越来越多的类型更容易。到底是细微的差别,说不定就随心所欲了。
      猜你喜欢
      • 2012-10-14
      • 1970-01-01
      • 1970-01-01
      • 2016-07-11
      • 2013-04-16
      • 1970-01-01
      • 1970-01-01
      • 2017-12-14
      • 2017-01-23
      相关资源
      最近更新 更多