wpf - 将 WPF UserControl 中的内容绑定(bind)到其属性的不同方法的优点/缺点是什么?

标签 wpf data-binding user-controls

开始使用 WPF UserControl 时,我偶然发现了几种将 UserControl 的内容绑定(bind)到其属性之一的方法。

这是我的控件的示例 C# 代码:

 public sealed partial class MyUserControl : UserControl
 {
    public MyUserControl()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty TheTextProperty =
        DependencyProperty.Register("TheText",
                                    typeof (string),
                                    typeof(MyUserControl),
                                    new FrameworkPropertyMetadata(0, 
                                        FrameworkPropertyMetadataOptions.
                                             BindsTwoWayByDefault)
            );

    public string TheText
    {
        get { return (string)GetValue(TheTextProperty); }
        set { SetValue(TheTextProperty, value); }
    }
}

下面是我发现的将内容绑定(bind)到该属性的不同方法:

内容使用与 RelativeSource/AncestorType 的绑定(bind)

<UserControl x:Class="MyUserControl"
             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">
    <StackPanel>
        <TextBox Text="{Binding TheText,
                        RelativeSource={RelativeSource
                                        AncestorType={x:Type UserControl}}}" />
    </StackPanel>
</UserControl>

可视化树根的DataContext在XAML中设置为UserControl

<UserControl x:Class="MyUserControl"
             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">
    <StackPanel DataContext="{Binding
                              RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
        <TextBox Text="{Binding TheText}" />
    </StackPanel>
</UserControl>

在构造函数中将可视化树根的DataContext设置为UserControl

<UserControl x:Class="MyUserControl"
             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">
    <StackPanel x:Name="VisualTreeRoot">
        <TextBox Text="{Binding TheText}" />
    </StackPanel>
</UserControl>

这是构造函数:

    public MyUserControl()
    {
        InitializeComponent();
        VisualTreeRoot.DataContext = this;
    }

最后但并非最不重要的一点:对在 WPF 中编写 UserControls 的其他新手的警告

我第一次想将 UserControl 的内容绑定(bind)到它的一个属性时,我想“嘿,让我们直接将 UserControl 的 DataContext 设置为其自身吧”:

<UserControl x:Class="MyUserControl"
             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"
             DataContext="{Binding RelativeSource={RelativeSource Self}}">

或者:

    public MyUserControl()
    {
        InitializeComponent();
        this.DataContext = this;
    }

但是,如果 UserControl 的用户想要将其属性绑定(bind)到其他绑定(bind)源,这不起作用。 UserControl 需要从其父级继承 DataContext 才能完成这项工作。通过如上所述覆盖它,绑定(bind)将不再找到它们的源。


我最后的问题:

  • 所介绍的每种方法的优点和缺点是什么?
  • 什么时候应该使用哪种方法?
  • 还有更多方法吗?

最佳答案

  • 在第一种情况下,TextBox 没有DataContext 设置为它的任何一个父级。因此,您必须告诉 TextBox 在 VisualTree 中的哪个位置是直接带有该属性的控件。
  • 第二种情况 DataContext 是在 StackPanel 上设置的,TextBox 相应地继承了它。如果您在 StackPanel
  • 中有多个控件,这比方法一更好
  • UserControl 本身上设置 DataContext 并不总是错误的(通过构造函数或 xaml)。我这样说是因为如果你有 20 个控件,其中 15 个需要使用在其当前 UserControl 类中定义的属性,5 个需要使用 UserControlDataContext,您始终可以对少数使用 RelativeSource FindAncestor 绑定(bind)。

只有我能想到的“方法”可以显示我提到的pt3是这样的

<!--  Can change type to another userControl too and specify Ancestorlevel  -->
<TextBlock Text="{Binding TheText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />

^^ 即使 TextBlock 的父级 UserControl 本身就是 DataContext

也能正常工作

至于何时使用什么。

这只是一个合乎逻辑的选择,如果您有多个 sibling 需要相同的 DataContext,则将 DataContext 设置为他们的 parent 是正确的答案。我总是倾向于将 DataContext 设置在可能的最顶层元素上,如果任何一个或两个项目需要变体,则相应地绑定(bind)它们。

如果在 MVVM 中,您的 VM 几乎总是成为 View 的顶级项目的 DataContext。其他一切都直接绑定(bind)到他们非常需要其属性的元素。

关于wpf - 将 WPF UserControl 中的内容绑定(bind)到其属性的不同方法的优点/缺点是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16854031/

相关文章:

c# - 带清除按钮的 WPF 组合框

wpf - 在名称范围内找不到名称 ---在数据网格中显示动画时出错

c# - 是否可以将复杂类型属性绑定(bind)到数据网格?

c# - 绑定(bind)到列表的组合框。向列表中添加新项目不会影响组合框

ASP.Net:动态添加到占位符的用户控件无法检索值

asp.net - 如何选择一个网页是否应该是Web用户控件?

javascript - Youtube JavaScript API - 播放任何一个 youtube 视频时暂停音频

wpf - 旋转 Canvas 不应旋转其子 Canvas

c# - 三元运算符叠加

javascript - VueJS 无法将输入绑定(bind)到 beforeMount Hook 中生成的属性