【问题标题】:What are the advantages/disadvantages of the different ways of binding content in a WPF UserControl to its properties?将 WPF UserControl 中的内容绑定到其属性的不同方式的优点/缺点是什么?
【发布时间】:2013-05-27 01:59:26
【问题描述】:

当开始使用 WPF 用户控件时,我偶然发现了几种将用户控件的内容绑定到其属性之一的方法。

这是我的控件的示例 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); }
    }
}

以下是我发现将内容绑定到此属性的不同方法:

内容使用与 RelativeSource/AncestorType 的绑定

<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 的内容绑定到它的一个属性时,我虽然“嘿,让我们直接将 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 的用户想要将其属性绑定到其他绑定源,这不起作用。 UserControl 需要从其父级继承 DataContext 才能使其工作。通过如上所示覆盖它,绑定将不再找到它们的源。


我最后的问题:

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

【问题讨论】:

    标签: wpf data-binding user-controls


    【解决方案1】:

    当绑定到自己的依赖属性时,我对用户控件使用元素绑定。

    <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"
             x:Name="uc">
       <StackPanel>
        <TextBox Text="{Binding ElementName=uc,Path=TheText}" />
    </StackPanel>
    </UserControl>
    

    【讨论】:

    • 好的,谢谢指出这个方法。我忘了在我上面的问题中包括这个。这种方法的优点/缺点是什么?
    • 我看不到缺点:)
    【解决方案2】:
    • 在第一种情况下,DataContext 没有设置为任何父级的TextBox。因此,您必须告诉 TextBox 在 VisualTree 中的哪个位置是直接在其上具有该属性的控件。
    • 第二种情况DataContext 设置在StackPanel 上,TextBox 相应地继承。如果您在 StackPanel 中有多个控件,这比方法一要好
    • UserControl 本身上设置DataContext 并不总是错误的(通过构造函数或xaml)。我这样说是因为如果您有 20 个控件,其中 15 个需要使用在其当前 UserControl 类中定义的属性,而 5 个需要使用 UserControlDataContext 的父级,则您始终可以使用 @987654333 @绑定少数派。

    只有我能想到的“方法”才能显示我提到的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,这也能正常工作

    至于什么时候用什么。

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

    如果在 MVVM 中,您的 VM 几乎总是成为视图顶级项目的 DataContext。其他所有内容都直接绑定到他们非常需要其属性的元素。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-13
      • 2017-05-18
      • 1970-01-01
      • 1970-01-01
      • 2015-04-18
      • 2012-05-23
      • 1970-01-01
      相关资源
      最近更新 更多