如何在 MVVM 框架中正确绑定到用户控件的依赖属性 [英] How to correctly bind to a dependency property of a usercontrol in a MVVM framework

查看:24
本文介绍了如何在 MVVM 框架中正确绑定到用户控件的依赖属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直无法找到一个干净、简单的示例,说明如何正确在 MVVM 框架内使用具有 DependencyProperty 的 WPF 实现用户控件.每当我为用户控件分配一个 DataContext 时,我下面的代码就会失败.

I have been unable to find a clean, simple, example of how to correctly implement a usercontrol with WPF that has a DependencyProperty within the MVVM framework. My code below fails whenever I assign the usercontrol a DataContext.

我正在尝试:

  1. 从调用 ItemsControl 设置 DependencyProperty ,和
  2. 使该 DependencyProperty 的值可用于被调用用户控件的 ViewModel.
  1. Set the DependencyProperty from the calling ItemsControl , and
  2. Make the value of that DependencyProperty available to the ViewModel of the called usercontrol.

我还有很多东西要学,衷心感谢您的帮助.

I still have a lot to learn and sincerely appreciate any help.

这是最顶层用户控件中的 ItemsControl,它使用 DependencyProperty TextInControl 调用 InkStringView 用户控件代码>(来自另一个问题的示例).

This is the ItemsControl in the topmost usercontrol that is making the call to the InkStringView usercontrol with the DependencyProperty TextInControl (example from another question).

<ItemsControl ItemsSource="{Binding Strings}" x:Name="self" >

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Vertical" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>


    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <DataTemplate.Resources>
                <Style TargetType="v:InkStringView">
                    <Setter Property="FontSize" Value="25"/>
                    <Setter Property="HorizontalAlignment" Value="Left"/>
                </Style>
            </DataTemplate.Resources>

            <v:InkStringView TextInControl="{Binding text, ElementName=self}"  />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

这是带有 DependencyPropertyInkStringView 用户控件.

Here is the InkStringView usercontrol with the DependencyProperty.

XAML:

<UserControl x:Class="Nova5.UI.Views.Ink.InkStringView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         x:Name="mainInkStringView"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>   
            <RowDefinition/>
        </Grid.RowDefinitions>

        <TextBlock Grid.Row="0" Text="{Binding TextInControl, ElementName=mainInkStringView}" />
        <TextBlock Grid.Row="1" Text="I am row 1" />
    </Grid>
</UserControl>

代码隐藏文件:

namespace Nova5.UI.Views.Ink
{
    public partial class InkStringView : UserControl
    {
        public InkStringView()
        {
            InitializeComponent();
            this.DataContext = new InkStringViewModel();   <--THIS PREVENTS CORRECT BINDING, WHAT
        }                                                   --ELSE TO DO?????

        public String TextInControl
        {
            get { return (String)GetValue(TextInControlProperty); }
            set { SetValue(TextInControlProperty, value); }
        }

        public static readonly DependencyProperty TextInControlProperty =
            DependencyProperty.Register("TextInControl", typeof(String), typeof(InkStringView));

    }
}

推荐答案

这是永远不要直接从 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.

这篇关于如何在 MVVM 框架中正确绑定到用户控件的依赖属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆