C# 与绑定混淆&;ContentTemplate中的DataContext

C# 与绑定混淆&;ContentTemplate中的DataContext,c#,wpf,C#,Wpf,考虑以下样式: <Window.Resources> <Style x:Key="NumberButton" TargetType="Button"> <Setter Property="Width" Value="Auto"/> <Setter Property="Height" Value="Auto"/> <Setter Property="Margin" Value="2"/&g

考虑以下样式:

<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

然而,我对绑定如何映射到
内容
属性感到困惑。我知道
ContentControl
的默认属性是
Content
属性,但我从未在
元素上显式设置
DataContext
。对我来说,这意味着按钮的DataContext为NULL,因此它将无法找到要显示的值


有人能解释一下,当我没有设置按钮的DataContext时,按钮的DataContext是如何被引用的吗?

对于大多数控件,如果没有设置
DataContext
,它将使用父级
DataContext
,通过继承的依赖属性完成<代码>内容控件和由此派生的控件,如按钮,工作方式稍有不同。如果您设置了这些
控件的
内容
,您还将
数据上下文
设置为内容。因此,在您的示例中,
DataContext
也是字符串“0”。Afair设置no
Content
将断开继承的链,因此该按钮内的
DataContext
将为空。

您的猜测是正确的
ContentControl的默认源属性为Content
。所以,通过这样做,
{Binding}
,您明确地告诉绑定引擎将标签的内容属性绑定到按钮的内容属性

但假设您要绑定到button的DataContext中的某个属性-绑定DummyDataContext的Name属性,则必须这样做(假设DummyDataContext在根窗口上设置为DataContext):


和在数据模板中

<Label Content="{Binding Name}" FontSize="20" FontFamily="Consolas"/>

按钮的内容指向类DummyDataContext的实例。因此,当您在标签上绑定
Content=“{Binding Name}”
时,您告诉它使用绑定到按钮内容的对象上的
Name
属性进行绑定


希望它现在有意义

DataContext
的特殊之处在于,它被设置为应用
的对象的
Content
属性

在这种情况下,
ContentTemplate
被应用于
按钮
,因此
ContentTemplate
中的
DataContext
被设置为该
按钮
内容
属性,而
按钮。Content
被设置为
“0”

如果将此
ContentTemplate
应用于具有不同
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>
我们这里有一个按钮。按钮的
DataContext
Content
属性设置为不同的值。该按钮还定义了一个
内容模板
,其中包含另一个
按钮
。此按钮的
内容
属性设置为不同的值

单击任一按钮将输出所单击按钮的
内容
数据上下文
。请记住,内部按钮嵌套在外部按钮中,因此当您单击它时,两个按钮的click方法都会得到处理

单击内部按钮的最终结果:

InnerButton.DataContext: OuterButton.Content InnerButton.Content: InnerButton.Content OuterButton.DataContext: OuterButton.DataContext OuterButton.Content: OuterButton.Content InnerButton.DataContext:OuterButton.Content InnerButton.Content:InnerButton.Content OuterButton.DataContext:OuterButton.DataContext 内容:OuterButton.Content
如您所见,
ContentTemplate
的特殊之处在于,它将
DataContext
设置为它所应用到的任何对象的
Content
属性。

这种行为变化取决于我假设的特定层次结构?在我的具体案例中,任何来自ContentControl的驱动都会自动设置数据上下文,正如您所解释的那样?我找不到任何关于这种行为的官方文件。我不同意你的回答。如果设置
ContentControl
Content
属性,或从
ContentControl
派生的控件,如
按钮
,则它也不会设置该控件的
DataContext
。但是,它确实使用
Content
属性作为应用于该控件的任何
ContentTemplate
DataContext
,这可能就是您所想的。例如:)是的,你是对的,瑞秋。离代码还有几天,而且已经开始忘记东西了。那么
{Binding}
没有绑定到
DataContext
的值,就像我在网上读的那样?它绑定到类的默认属性?我听到了这么多相互矛盾的信息,这让我非常困惑:(你所说的也与Rachel在回答中所说的直接矛盾。你在这里混淆了事情。我在她的回答中也提到了Rachel所说的-
的DataContext是特殊的,因为它被设置为要应用的对象的Content属性。
{Binding}与你读过的其他内容相比,内部内容模板的内容有所不同。Rachel,你总是让学习WPF变得更容易!!我将你的作为新答案标记。非常感谢,这让我非常清楚。
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));
}
InnerButton.DataContext: OuterButton.Content InnerButton.Content: InnerButton.Content OuterButton.DataContext: OuterButton.DataContext OuterButton.Content: OuterButton.Content