2010-03-11 19 views
5

Definisco un modello di intestazione in una casella di gruppo wpf e il databinding non funziona. Non capisco perché.WPF GroupBox HeaderTemplate e 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> 

risposta

1

Il GroupBox non ha un membro chiamato "CurrentContract". Molto probabilmente, vuoi accedere a una proprietà chiamata "CurrentContract" dal corrispondente ViewModel ?! Il ViewModel è DataContext del GroupBox, quindi bisogna modificare i percorsi vincolanti per qualcosa di simile ...

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

Grazie.Penso che per impostazione predefinita in associazione dati, wpf ottiene sempre i dati dalla proprietà DataContext. Sembra non nel datatemplate. – Coolweb

+1

Oppure, in alternativa, puoi associare DataContext all'intestazione facendo qualcosa come Header = "{Binding}" nella dichiarazione GroupBox. In questo modo il tuo DataTemplate funzionerà così com'è. Vedi la mia risposta per maggiori dettagli. – jpierson

1

la lezione di cui sopra è utile in generale per DataTemplates, ma in realtà ho scoperto di recente v'è un modo migliore per modificare l'intestazione di una casella di gruppo:

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

In questo modo non è necessario definire una sorgente relativa nei binding.

Si prega di notare anche this issue con GroupBox e l'intestazione.

+0

L'impostazione del contenuto visivo direttamente sulla proprietà Header funziona correttamente ma non vi è alcun motivo per evitare HeaderTemplate se si capisce come funziona. Si prega di vedere la mia risposta per una spiegazione. – jpierson

21

Il problema è che il HeaderTemplate viene utilizzato per modellare l'intestazione in tal modo all'interno della vostra HeaderTemplateDataContext è tutto ciò che legherai o assegnare alla Header proprietà della vostra GroupBox.

Pensare alla proprietà Header come quasi come DataContext per l'intestazione del controllo. Normalmente la proprietà DataContext inhierisce il suo valore dal suo genitore ma poiché non tutti i controlli hanno un Header l'intestazione è vuota a meno che non lo si imposti.

Associando esplicitamente l'intestazione al DataContext corrente Header="{Binding}", l'esempio dovrebbe funzionare come previsto. Per aiutare a illustrare come funziona, ho creato un semplice esempio qui sotto che mostra come ile il DataContext funzionano indipendentemente l'uno dall'altro per fornire dati al corpo o all'intestazione del controllo.

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

Ciò comporterà una GroupBox che sia simile alla seguente.

GroupBox with templated header

penso che per impostazione predefinita in databinding, WPF ottiene sempre i dati dalla proprietà DataContext. Sembra che non in datatemplate

La tua ipotesi è corretta su DataContext e lo fa lavoro nel DataTemplate come ho dimostrato è solo che nel modello del Header il DataContext è il valore della proprietà di intestazione e non il DataContext stesso.

+2

+1, questa informazione aiuta davvero come funziona l'intestazione nelle caselle di gruppo! – Mas

+0

Si noti che queste osservazioni sono valide anche in generale per qualsiasi HeaderedContentControl. – jpierson

+0

Il più importante di questa risposta è che è necessario impostare l'intestazione = "{Binding}" se si intende utilizzare l'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> 

Proprio propagare la DC GroupBox al contenuto DataTemplate ... funziona come un fascino ...

+0

Questo è ciò che è più semplice, penso. Grazie. –

0

Questo è ciò che ha funzionato per me:

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