将WPF UserControl中的内容绑定到其属性的不同方法有哪些优点/缺点?

时间:2013-05-31 09:25:27

标签: wpf data-binding user-controls

当开始使用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才能使其工作。如上所述,通过覆盖它,绑定将不再找到它们的来源。


我的最后一个问题:

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

2 个答案:

答案 0 :(得分:2)

我在绑定到自己的依赖项属性时对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"
         x:Name="uc">
   <StackPanel>
    <TextBox Text="{Binding ElementName=uc,Path=TheText}" />
</StackPanel>
</UserControl>

答案 1 :(得分:2)

  • 在第一种情况下,DataContext设置为任何父级的TextBox都没有TextBox。因此,你必须告诉DataContext VisualTree中的哪个是直接控制该属性的控件。
  • 第二个案例StackPanel设置在TextBox StackPanel相应地继承DataContext。如果UserControl
  • 中有多个控件,这比接近一个更好
  • UserControl上设置UserControl本身并不总是错误的(通过构造函数或xaml)。我这样说是因为如果你有20个控件,其中15个需要使用在其当前DataContext类中定义的属性,5个需要是RelativeSource FindAncestor的{​​{1}}的父级,你总是可以对少数群体使用<!-- Can change type to another userControl too and specify Ancestorlevel --> <TextBlock Text="{Binding TheText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" /> 绑定。

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

TextBlock

^^即使UserControl的父DataContext有自己DataContext

,这也会正常工作

至于何时使用什么。

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

如果在MVVM中,您的VM几乎总是成为View的顶级项目的{{1}}。其他一切直接绑定到他们需要的属性的元素。