且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在 MVVM 框架中正确绑定到用户控件的依赖属性

更新时间:2021-12-25 02:33:27

这是永远不要直接从 UserControl 本身设置 DataContext 的众多原因之一.

That is one of the many reasons you should never set the DataContext directly from the UserControl itself.

当你这样做时,你不能再使用任何其他 DataContext,因为 UserControl 的 DataContext 被硬编码到一个只有 UserControl 的实例代码> 可以访问,这违背了 WPF 具有独立 UI 和数据层的最大优势之一.

When you do so, you can no longer use any other DataContext with it because the UserControl's DataContext is hardcoded to an instance that only the UserControl has access to, which kind of defeats one of WPF's biggest advantages of having separate UI and data layers.

WPF中UserControls主要有两种使用方式

There are two main ways of using UserControls in WPF

  1. 一个独立的 UserControl,可以在任何地方使用而无需特定的 DataContext.

  1. A standalone UserControl that can be used anywhere without a specific DataContext being required.

这种类型的 UserControl 通常为它需要的任何值公开 DependencyProperties,并且会像这样使用:

This type of UserControl normally exposes DependencyProperties for any values it needs, and would be used like this:

<v:InkStringView TextInControl="{Binding SomeValue}" />

我能想到的典型示例是任何通​​用的东西,例如日历控件或弹出控件.

Typical examples I can think of would be anything generic such as a Calendar control or Popup control.

一个 UserControl,仅用于特定的 ModelViewModel.

A UserControl that is meant to be used with a specific Model or ViewModel only.

这些 UserControls 对我来说更常见,并且可能是您正在寻找的.我将如何使用这样的 UserControl 的一个例子是:

These UserControls are far more common for me, and is probably what you are looking for in your case. An example of how I would use such a UserControl would be this:

<v:InkStringView DataContext="{Binding MyInkStringViewModelProperty}" />

或者更频繁地,它将与隐式 DataTemplate 一起使用.隐式 DataTemplate 是带有 DataType 且没有 KeyDataTemplate,WPF 将在任何时候自动使用此模板想要呈现指定类型的对象.

Or more frequently, it would be used with an implicit DataTemplate. An implicit DataTemplate is a DataTemplate with a DataType and no Key, and WPF will automatically use this template anytime it wants to render an object of the specified type.

<Window.Resources>
    <DataTemplate DataType="{x:Type m:InkStringViewModel}">
        <v:InkStringView />
    </DataTemplate>
<Window.Resources>

<!-- Binding to a single ViewModel -->
<ContentPresenter Content="{Binding MyInkStringViewModelProperty}" />

<!-- Binding to a collection of ViewModels -->
<ItemsControl ItemsSource="{Binding MyCollectionOfInkStringViewModels}" />

使用此方法时不需要 ContentPresenter.ItemTemplateItemsControl.ItemTemplate.

No ContentPresenter.ItemTemplate or ItemsControl.ItemTemplate is needed when using this method.

不要把这两种方法混在一起,效果不好:)

Don't mix these two methods up, it doesn't go well :)

无论如何,更详细地解释您的具体问题

But anyways, to explain your specific problem in a bit more detail

当您像这样创建 UserControl 时

When you create your UserControl like this

<v:InkStringView TextInControl="{Binding text}"  />

你基本上是在说

var vw = new InkStringView()
vw.TextInControl = vw.DataContext.text;

vw.DataContext 未在 XAML 中的任何位置指定,因此它是从父项继承的,这导致

vw.DataContext is not specified anywhere in the XAML, so it gets inherited from the parent item, which results in

vw.DataContext = Strings[x];

因此您设置 TextInControl = vw.DataContext.text 的绑定是有效的,并且在运行时解析得很好.

so your binding that sets TextInControl = vw.DataContext.text is valid and resolves just fine at runtime.

但是,当您在 UserControl 构造函数中运行它时

However when you run this in your UserControl constructor

this.DataContext = new InkStringViewModel();

DataContext 被设置为一个值,因此不再自动从父级继承.

the DataContext is set to a value, so no longer gets automatically inherited from the parent.

所以现在运行的代码如下所示:

So now the code that gets run looks like this:

var vw = new InkStringView()
vw.DataContext = new InkStringViewModel();
vw.TextInControl = vw.DataContext.text;

当然,InkStringViewModel 没有名为 text 的属性,因此绑定在运行时失败.

and naturally, InkStringViewModel does not have a property called text, so the binding fails at runtime.