3

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

这是我的控件的示例 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 才能使其工作。通过如上所述覆盖它,绑定将不再找到它们的源。


我最后的问题:

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

2 回答 2

2
  • 那么在第一种情况下,它的任何一个父级都没有设置DataContextTextBox因此,您必须直接告诉TextBoxVisualTree 中具有该属性的控件的位置。
  • 第二种情况DataContext是设置继承的StackPanelTextBox如果您有多个控件,这比方法一要好StackPanel
  • 设置本身并不总是错误DataContext的(通过构造函数或 xaml)。UserControl我这样说是因为如果您有 20 个控件,其中 15 个需要使用在其当前类中定义的属性,而 5 个需要使用'sUserControl的父级,则您始终可以对少数人使用绑定。UserControlDataContextRelativeSource FindAncestor

只有我能想到的“方法”可以显示我提到的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 中,您的 VMDataContext几乎总是成为视图的顶级项目。其他一切都直接绑定到他们非常需要其属性的元素。

于 2013-05-31T09:48:39.150 回答
2

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

<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>
于 2013-05-31T09:41:30.923 回答