UserControl的DataContext

时间:2011-02-22 11:16:40

标签: wpf xaml datacontext

我正在创建一个UserControl我想使用这样的东西:

<controls:ColorWithText Color="Red" Text="Red color" />

到目前为止,我已经实现了类似的控件:

<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
    <StackPanel Orientation="Horizontal" >
        <Border Width="15" Height="15" Background="{Binding Color, ElementName=ThisControl}" />
        <TextBlock Text="{Binding Text, ElementName=ThisControl}" />
    </StackPanel>
</UserControl>

其中ColorText是代码中定义的控件的依赖项属性。这有效,但每次都指定ElementName似乎没必要。

另一个可行的选择是使用

<UserControl x:Class=… DataContext="{Binding ElementName=ThisControl}" Name="ThisControl">

并没有指定ElementName,但这对我来说似乎也不是一个干净的解决方案。

我有两个问题:

  1. 为什么<UserControl DataContext="{RelativeSource Self}">无效?
  2. 这样做的最佳方式是什么?

5 个答案:

答案 0 :(得分:57)

首先,请尝试:

<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}">

对于第二个问题,我认为使用ElementNameAncestorBinding是绑定UserControl属性的最佳方式。

答案 1 :(得分:18)

为什么不能使用<UserControl DataContext="{RelativeSource Self}">

这是您使用控件的方式

<Grid DataContext="{StaticResource ViewModel}">
    <!-- Here we'd expect this control to be bound to -->
    <!-- ColorToUse on our ViewModel resource          -->
    <controls:ColorWithText Color="{Binding ColorToUse}" />
</Grid>

现在因为我们在控件中对数据上下文进行了硬编码,它将尝试在 ColorWithText对象上查找ColorToUse属性,而不是ViewModel,这显然会失败。

这就是您无法在用户控件上设置DataContext的原因。感谢Brandur让我了解这一点。

做这样的事情的最佳方式是什么?

相反,您应该在控件中的第一个子UI元素中设置DataContext。

在你的情况下你想要

<StackPanel 
  DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
  Orientation="Horizontal" >

现在你有一个DataContext引用你的控件,所以你可以使用相对绑定访问该控件的任何属性。

答案 2 :(得分:13)

你应该使用

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=Color}

用于数据绑定相关疑问总是参考此表 http://www.nbdtech.com/Blog/archive/2009/02/02/wpf-xaml-data-binding-cheat-sheet.aspx

答案 3 :(得分:10)

您可以在构造函数本身将datacontext设置为self。

public ColorWithText()
{
 InitializeComponent();
 DataContext = this;
}

现在你可以简单地说

<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
    <StackPanel Orientation="Horizontal" >
        <Border Width="15" Height="15" Background="{Binding Color}" />
        <TextBlock Text="{Binding Text}" />
    </StackPanel>
</UserControl>

答案 4 :(得分:10)

我知道这已得到解答,但没有一个解释能够理解DataContext及其工作原理。这个链接做得很好。

EVERYTHING YOU WANTED TO KNOW ABOUT DATABINDING IN WPF, SILVERLIGHT AND WP7 (PART TWO)

回答你的问题#1

为什么<UserControl DataContext="{RelativeSource Self}">无效?

这是上述链接的摘要。 不应在UserControl元素级别将DataContext设置为Self。这是因为它破坏了DataContext的继承。如果您将其设置为self并将此控件放在Window或其他控件上,则它将不会继承Windows DataContext。

DataContext继承到XAML的所有下层元素和UserControls的所有XAML,除非它被覆盖在某处。通过将UserControl DataContext设置为自身,这将覆盖DataContext并中断继承。相反,将它放在XAML中的一个元素深处,在您的情况下,StackPanel。将DataContext绑定放在此处并将其绑定到UserControl。这保留了继承。

有关详细说明,请参阅下面的链接。

A SIMPLE PATTERN FOR CREATING RE-USEABLE USERCONTROLS IN WPF / SILVERLIGHT

回答你的问题#2
做这样的事情最好的方法是什么?

请参阅下面的代码示例。

<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
    <StackPanel Orientation="Horizontal" DataContext={Binding ElementName=ThisControl}>
    <Border Width="15" Height="15" Background="{Binding Color" />
    <TextBlock Text="{Binding Text}" />
</StackPanel>

请注意,执行此操作后,每个绑定都不需要ElementName。