考虑以下风格:
<Window.Resources>
<Style x:Key="NumberButton" TargetType="Button">
<Setter Property="Width" Value="Auto"/>
<Setter Property="Height" Value="Auto"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Label Content="{Binding}" FontSize="20" FontFamily="Consolas"/>
</DataTemplate>
</Setter.Value>
</Setter>
<EventSetter Event="Click" Handler="OnClicked"/>
</Style>
</Window.Resources>
我的目标是能够创建多个按钮,每个按钮代表0-9。例如,这是数字0的按钮:
<Button Grid.Row="3" Grid.Column="1" Style="{StaticResource NumberButton}" Content="0"/>
我对DataContext如何工作的理解是,如果你没有在XAML中显式设置它,它应该是NULL,它指示绑定使用父的DataContext。这是传递性的,因此它会继续向上移动每个父级,直到它找到要使用的显式设置的DataContext。
但我对我的绑定如何映射到Content
属性感到困惑。我知道ContentControl
的默认属性是Content
属性,但我从未在DataContext
元素上明确设置<Button>
。对我来说,这意味着Button的DataContext为NULL,因此无法找到要显示的值。
有人可以解释当我没有设置Button的DataContext时如何引用它?
答案 0 :(得分:7)
DataContext
的{{1}}非常特殊,因为它被设置为<ContentTemplate>
正在应用的对象的Content
属性。
在这种情况下,<ContentTemplate>
正在应用于ContentTemplate
,因此Button
内的DataContext
设置为ContentTemplate
属性Content
,Button
设置为Button.Content
如果您将此"0"
应用于具有不同ContentTemplate
属性的其他Button
,则会改为使用Content
属性。
这是一个简单的例子,我希望能更好地证明这一点。
Content
<Button x:Name="OuterButton" Click="Button_Click">
<!-- // Set DataContext to a string equal to "OuterButton.DataContext" -->
<Button.DataContext>
OuterButton.DataContext
</Button.DataContext>
<!-- // Set Content to a string equal to "OuterButton.DataContext" -->
<Button.Content>
OuterButton.Content
</Button.Content>
<Button.ContentTemplate>
<DataTemplate>
<StackPanel>
<Button x:Name="InnerButton" Content="InnerButton.Content" Click="Button_Click" />
<TextBlock FontWeight="Bold" Text="{Binding }"/>
</StackPanel>
</DataTemplate>
</Button.ContentTemplate>
</Button>
我们这里有一个按钮。 Button的private void Button_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
Debug.WriteLine(string.Format("{0}.DataContext: {1}", btn.Name, btn.DataContext));
Debug.WriteLine(string.Format("{0}.Content: {1}", btn.Name, btn.Content));
}
和DataContext
属性设置为不同的值。该按钮还定义了Content
,其中包含另一个ContentTemplate
。此按钮的Button
属性设置为不同的值。
单击任一按钮将输出单击按钮的Content
和Content
。请记住,内部按钮嵌套在OuterButton中,因此当您单击它时,将为两个按钮处理Click方法。
点击内部按钮的最终结果:
InnerButton.DataContext: OuterButton.Content InnerButton.Content: InnerButton.Content OuterButton.DataContext: OuterButton.DataContext OuterButton.Content: OuterButton.Content
正如您所看到的,DataContext
的特殊之处在于它将ContentTemplate
设置为应用它的任何对象的DataContext
属性。
答案 1 :(得分:1)
您的猜测是正确的default source property for ContentControl is Content
。因此,通过执行此{Binding}
,您明确告知绑定引擎将Label的内容属性与按钮的Content属性绑定。
但是假设您要绑定到按钮的DataContext中的某个属性 - DummyDataContext的名称属性,则必须这样做(假设DummyDataContext在根窗口上设置为DataContext < / em>的):
<Button Style="{StaticResource CalcButton}" Content="{Binding}"/>
和DataTemplate
<Label Content="{Binding Name}" FontSize="20" FontFamily="Consolas"/>
Button的内容指向DummyDataContext类的实例。因此,当您在标签上绑定Content="{Binding Name}"
时,您告诉它绑定到绑定到Button内容的对象上的Name
属性。
希望现在有道理.. !!
答案 2 :(得分:0)
对于大多数控件,如果未设置DataContext
,则使用父DataContext
,通过继承的依赖项属性完成。 ContentControls
和派生的控件,就像Button
一样,工作方式略有不同。如果您设置这些Content
的{{1}},则还会将Controls
设置为内容。因此,在您的情况下,您的DataContext
也是字符串“0”。根本没有DataContext
设置会破坏继承链,因此该按钮内的Content
将为空。