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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31729594/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:18:41  来源:igfitidea点击:

How Can I bind DataContext to a Generic ViewModel in XAML?

c#wpfxamlgenericsmvvm

提问by a.toraby

Suppose we have a generic View model like this:

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

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

When I want to bind this View Model to DataContextof my UserControlin XAML, I can not! XAML editor does not find My View Model class. How should I refer to a generic type in XAML?

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

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

In the above code sis an alias for my workspace, and If I convert my generic View Model to a concrete class it works normally.

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

回答by Mike Eason

When working with XAML, you cannot instantiate a view model with a generic parameter in XAML code.

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

To work around this, you need to make use of inheritance, here's an example:

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

public abstract class ViewModel<T>

Usage:

用法:

public class MovieViewModel : ViewModel<Movie>

...

public class GenreViewModel : ViewModel<Genre>

Creating a new class for each model seemsto be a bit stupid, however this simply isn't true. By making the assumption that each view model contains one model, you've pretty much set yourself up for following this pattern in all view models, as your base view model enforcesthis constraint.

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

I personally use the pattern of using a ViewModel<T>base class, where Tis the model.

我个人使用使用ViewModel<T>基类T的模式,模型在哪里。

It's certainly a good idea to keep the logic separated from your base view model. A view model for each model is in fact a very good pattern to implement.

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



There is another way you can achieve what you're after, this is simply removing the generic from the view model base, consider the example:

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

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

Now, if you populate Modelwith let's say a Movie, then XAML will see it as a Movie, and not an object. Now this is pretty nifty as far as your XAML side goes, however, when you start working with this model in C#, then you're going to have all sorts of problems as you'll have to cast the object to whatever type you are using. So I wouldn't recommend this at all.

现在,如果您Model使用 a填充Movie,那么 XAML 会将其视为 a Movie,而不是object。现在,就您的 XAML 方面而言,这是非常漂亮的,但是,当您开始在C# 中使用此模型时,您将遇到各种各样的问题,因为您必须将对象转换为任何类型使用。所以我根本不会推荐这个。



Another method of getting around this would be to set the DataContextin code-behind, and if you're going to do that, then, well, only God can save you now. The main ideas around the MVVM design pattern is the separation of View logic and the Business layer (View Models), as soon as your View starts instantiating view models then that nice separation is lost.

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

Now saying that, there's nothing stopping you from doing this, I've said this many times before. MVVM is a design pattern, not the law, if you want to set the DataContextin code-behind, then fair enough, however it's important that you are aware of the implications.

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

回答by Glen Thomas

You could create a class that inherits from your generic ViewModel and use that

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

public class PersonViewModel : ViewModel<Person>

XAML:

XAML:

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

回答by Anthony Russell

You're not capable of setting a generic viewmodel in XAML because XAML requires known types at compile time.

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

Dependency injection is your best bet

依赖注入是你最好的选择

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

回答by tomab

If your ViewModel is derived from a base class, let's say NonGenericViewModel then you can assign in code behind an object of type NonGenericViewModel to the DataContext. Using this way you still have the benefits of generics and the data binding will also work because the bindings will be made during runtime, no matter what type of object you assign to DataContext as long as it has properties, collections, etc required by your xaml controls.

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

BaseViewModel<T> : NonGenericViewModel { ... }

NonGenericViewModel : INotifyPropertyChanged { ... }

And in code behind, in the ctor of your xaml.cs:

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

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

Even this is correct and working:

即使这是正确且有效的:

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

It depends if you need or not the class NonGenericViewModel in other places.

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