2010-03-11 4 views
5

Je définis un headertemplate dans une zone de groupe wpf et la liaison de données ne fonctionne pas. Je ne comprends pas pourquoi.WPF GroupBox HeaderTemplate et DataBinding

<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> 

Répondre

1

GroupBox n'a pas de membre appelé "CurrentContract". Très probablement, vous voulez accéder à une propriété appelée "CurrentContract" à partir du ViewModel correspondant ?! Le ViewModel est le DataContext de GroupBox, donc vous devez changer les chemins de liaison à quelque chose comme ...

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

Merci.Je pense que par défaut dans la liaison de données, wpf obtient toujours des données de la propriété DataContext. Ne semble pas dans le datatemplate. – Coolweb

+1

Vous pouvez également lier le DataContext à l'en-tête en faisant quelque chose comme Header = "{Binding}" dans votre déclaration GroupBox. De cette façon, votre DataTemplate fonctionnera tel quel. Voir ma réponse pour plus de détails. – jpierson

1

La leçon apprise ci-dessus est utile en général pour DataTemplates, mais j'ai trouvé récemment il y a une meilleure façon de changer l'en-tête d'un groupbox:

<GroupBox> 
    <GroupBox.Header> 
     <CheckBox IsChecked="{Binding Path=mSomeBoolean}"/> 
    </GroupBox.Header> 
</GroupBox> 

de cette façon, il n'y a pas besoin de définir une source relative dans les liaisons.

Veuillez également noter this issue avec GroupBox et l'en-tête.

+0

La définition du contenu visuel directement sur la propriété Header fonctionne très bien, mais il n'y a aucune raison d'éviter HeaderTemplate si vous comprenez comment cela fonctionne. S'il vous plaît voir ma réponse pour une explication. – jpierson

21

Le problème est que le HeaderTemplate est utilisé pour Templating l'en-tête ainsi dans le HeaderTemplate votre DataContext est tout ce que vous lierez ou attribuer à la propriété Header de votre GroupBox.

Pensez à la propriété Header comme presque DataContext pour l'en-tête du contrôle. Normalement, la propriété DataContext ne possède pas sa valeur par rapport à son parent, mais puisque tous les contrôles ne possèdent pas Header, l'en-tête est vide à moins que vous ne l'ayez défini.

En liant explicitement votre en-tête au DataContext actuel Header="{Binding}" votre exemple devrait fonctionner comme prévu. Pour illustrer comment cela fonctionne, j'ai créé un exemple simple ci-dessous qui montre comment les Header et DataContext fonctionnent indépendamment les uns des autres pour fournir des données au corps ou à l'en-tête du contrôle.

<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> 

Ceci donnera GroupBox qui ressemble à ceci.

GroupBox with templated header

Je pense que par défaut dans databinding, WPF obtient toujours des données de la propriété DataContext. Semble pas datatemplate

Votre hypothèse est correcte au sujet DataContext et il fonctionne dans le DataTemplate comme je l'ai démontré, il est juste que dans le modèle de l'en-tête DataContext est la valeur de l'en-tête de la propriété et non le DataContext lui-même.

+2

+1, cette information aide vraiment à la façon dont l'en-tête fonctionne dans les boîtes de groupe! – Mas

+0

Notez que ces observations sont également vraies en général pour tout HeaderedContentControl. – jpierson

+0

Le plus important à retenir de cette réponse est que vous devez définir Header = "{Binding}" si vous allez utiliser HeaderTemplate. – stricq

3
<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> 

Juste GroupBox se propagent DC au contenu DataTemplate ... fonctionne comme un charme ...

+0

C'est ce qui est le plus facile, je pense. Merci. –

0

C'est ce qui a fonctionné pour moi:

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