WPF GroupBox的HeaderTemplate和DataBinding

8

我在一个WPF GroupBox中定义了一个HeaderTemplate,但数据绑定不起作用。我不明白为什么。

<GroupBox>
<GroupBox.HeaderTemplate>
            <DataTemplate>
            <StackPanel Orientation="Horizontal" >
                <Image Source="/PopuAssuNetApplication.UI.Control;component/Images/Members.png" Width="24" />
                <TextBlock VerticalAlignment="Center">
                                <TextBlock.Text>
                                        <MultiBinding StringFormat="{x:Static Member=resx:Resources.PersonsInContractGroupBox}"> 
                                            <Binding Path="CurrentContract.Federation" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type GroupBox}}">
                                            </Binding>
                                            <Binding Path="CurrentContract.Type" Converter="{StaticResource contractTypeConverter}" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type GroupBox}}">
                                            </Binding>
                                            <Binding Path="CurrentContract.Number" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type GroupBox}}">
                                            </Binding>
                                        </MultiBinding>
                                    </TextBlock.Text>
                </TextBlock>
                <WpfComponent:WaitControl Margin="7,0,0,0" VerticalAlignment="Top" Width="24" Height="24" MarginCenter="4">
                    <WpfComponent:WaitControl.Style>
                        <Style>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Path=IsMembersOfContractBusy, UpdateSourceTrigger=PropertyChanged, ElementName=PersonsInContract}" Value="true">
                                    <Setter Property="WpfComponent:WaitControl.Visibility" Value="Visible" />
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Path=IsMembersOfContractBusy, UpdateSourceTrigger=PropertyChanged, ElementName=PersonsInContract}" Value="false">
                                    <Setter Property="WpfComponent:WaitControl.Visibility" Value="Collapsed" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </WpfComponent:WaitControl.Style>
                </WpfComponent:WaitControl>
            </StackPanel>
                </DataTemplate>
        </GroupBox.HeaderTemplate>

5个回答

29
问题在于HeaderTemplate用于模板化标题,因此在HeaderTemplate内,你的DataContext是绑定或赋值给GroupBoxHeader属性的任何内容。
可以将Header属性看作控件标题的DataContext。通常情况下,DataContext属性会从其父级继承其值,但由于并不是每个控件都有Header属性,因此如果不设置它,则标题为空白。
通过显式地将标题绑定到当前DataContext Header="{Binding}",你的示例应该按照期望工作。为了帮助说明如何使用HeaderDataContext分别为控件的主体或标题提供数据,我创建了一个简单的示例,如下所示。
<GroupBox Header="HEADER TEXT" DataContext="BODY TEXT">
    <GroupBox.HeaderTemplate>
        <DataTemplate>
            <Button Content="{Binding}"
                    Background="LightGreen" />
        </DataTemplate>
    </GroupBox.HeaderTemplate>

    <CheckBox HorizontalAlignment="Center"
                VerticalAlignment="Center" Content="{Binding}" />
</GroupBox>
这将产生一个类似以下图片的GroupBox
GroupBox with templated header

我想默认情况下在databinding中,wpf总是从DataContext属性获取数据。但在datatemplate中好像不是这样。

你的假设是正确的,关于DataContext,它确实可以在DataTemplate中使用,正如我所演示的那样。只是在Header模板中,DataContext是Header属性的值而不是DataContext本身。


2
+1,这个信息真的很有帮助,可以解决组框中标题栏的工作方式! - Mas
请注意,这些观察结果同样适用于任何HeaderedContentControl。 - jpierson
这个答案最重要的要点是,如果你要使用HeaderTemplate,那么你需要设置Header="{Binding}"。 - stricq

9

GroupBox没有名为"CurrentContract"的成员。很可能,您想从相应的ViewModel中访问名为"CurrentContract"的属性? ViewModel是GroupBox的DataContext,因此您必须更改绑定路径,例如...

<Binding Path="DataContext.CurrentContract.Type" Converter="{StaticResource contractTypeConverter}" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type GroupBox}}">

1
谢谢。我认为在数据绑定中,默认情况下,WPF总是从DataContext属性获取数据。但在DataTemplate中似乎不是这样。 - Coolweb
1
或者,您可以通过在GroupBox声明中执行类似Header="{Binding}"的操作将DataContext绑定到Header。这样,您的DataTemplate将按原样工作。有关更多详细信息,请参见我的答案。 - jpierson

5
    <GroupBox >
        <GroupBox.HeaderTemplate>
            <DataTemplate>
                    <RadioButton Content="myR"
                            IsChecked="{Binding rIsChecked, Mode=TwoWay}"
                            DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GroupBox}}}" />
            </DataTemplate>
        </GroupBox.HeaderTemplate>
        <GroupBox.Content>
            <Grid IsEnabled="{Binding rIsChecked}">
            </Grid>
        </GroupBox.Content>
    </GroupBox>

只需将 GroupBox DC 传递给 DataTemplate 内容即可……非常流畅易懂。

1
这是我认为最简单的。谢谢。 - Mark Bonafe

1
上述所学对于DataTemplates总体上是有用的,但我最近发现了一种更好的方法来改变GroupBox的标题:
<GroupBox>
    <GroupBox.Header>
        <CheckBox IsChecked="{Binding Path=mSomeBoolean}"/>
    </GroupBox.Header>
</GroupBox>

这样就不需要在绑定中定义相对源。

另外请注意 GroupBoxes和标题的问题


将可视内容直接设置在Header属性上可以正常工作,但如果您了解它的工作原理,没有理由避免使用HeaderTemplate。请参阅我的答案以获取说明。 - jpierson

0

这是对我有效的方法:

<HeaderedContentControl Header="{Binding}" Style="{StaticResource TallHeaderedContentStyle}">
  <HeaderedContentControl.HeaderTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Path=HeaderText"} />
    </DataTemplate>
  </HeaderedContentControl.HeaderTemplate>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接