2011-10-05 14 views
57

Ho un datagrid con una Riga che ha un'immagine. Questa immagine è associata a un trigger per un determinato stato. Quando lo stato cambia, voglio cambiare l'immagine.Errore WPF: impossibile trovare Governance FrameworkElement per l'elemento di destinazione

Il modello stesso è impostato su HeaderStyle di DataGridTemplateColumn. Questo modello ha alcuni vincoli. Il primo Giorno vincolante mostra che giorno è e lo Stato cambia l'immagine con un grilletto.

Queste proprietà sono impostate in un ViewModel.

Proprietà:

public class HeaderItem 
{ 
    public string Day { get; set; } 
    public ValidationStatus State { get; set; } 
} 

this.HeaderItems = new ObservableCollection<HeaderItem>(); 
     for (int i = 1; i < 15; i++) 
     { 
      this.HeaderItems.Add(new HeaderItem() 
      { 
       Day = i.ToString(), 
       State = ValidationStatus.Nieuw, 
      }); 
     } 

DataGrid:

<DataGrid x:Name="PersoneelsPrestatiesDataGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
       AutoGenerateColumns="False" SelectionMode="Single" ItemsSource="{Binding CaregiverPerformances}" FrozenColumnCount="1" > 

    <DataGridTemplateColumn HeaderStyle="{StaticResource headerCenterAlignment}" Header="{Binding HeaderItems[1]}" Width="50"> 

       <DataGridTemplateColumn.CellEditingTemplate> 
        <DataTemplate> 
         <TextBox Text="{ Binding Performances[1].Duration,Converter={StaticResource timeSpanConverter},Mode=TwoWay}"/> 
        </DataTemplate> 
       </DataGridTemplateColumn.CellEditingTemplate> 
       <DataGridTemplateColumn.CellTemplate> 
        <DataTemplate> 
         <TextBlock TextAlignment="Center" Text="{ Binding Performances[1].Duration,Converter={StaticResource timeSpanConverter}}"/> 
        </DataTemplate> 
       </DataGridTemplateColumn.CellTemplate> 
      </DataGridTemplateColumn> </DataGrid> 

Datagrid HeaderStyleTemplate:

<Style x:Key="headerCenterAlignment" 
      TargetType="{x:Type DataGridColumnHeader}"> 
     <Setter Property="HorizontalContentAlignment" Value="Center"/> 

     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type DataGridColumnHeader}"> 
        <Grid> 
         <Grid.RowDefinitions> 
          <RowDefinition /> 
          <RowDefinition /> 
         </Grid.RowDefinitions> 

         <TextBlock Grid.Row="0" Text="{Binding Day}" /> 
         <Image x:Name="imageValidation" Grid.Row="1" Width="16" Height="16" Source="{StaticResource imgBevestigd}" /> 
        </Grid> 

        <ControlTemplate.Triggers> 
         <MultiDataTrigger > 
          <MultiDataTrigger.Conditions> 
           <Condition Binding="{Binding State}" Value="Nieuw"/>         
          </MultiDataTrigger.Conditions> 
          <Setter TargetName="imageValidation" Property="Source" Value="{StaticResource imgGeenStatus}"/> 
         </MultiDataTrigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 

Ora, quando il progetto di avvio le immagini non mostra e ottengo questo errore:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=HeaderItems[0]; DataItem=null; target element is 'DataGridTemplateColumn' (HashCode=26950454); target property is 'Header' (type 'Object')

Perché viene visualizzato questo errore?

+1

Ho controllato la soluzione con risposta sopra, ma nel mio caso non funziona. Quando passo a un'altra soluzione come nel link http: //www.thomaslevesque.com/2011/03/21/WPF-how-to-bind-to-data-quando-il-DataContext-è-non-ereditato /. L'idea è la stessa della soluzione, invece di usare FrameworkElement, hanno creato un'altra classe. Quindi funziona per me. – leo5th

+0

Per gli altri che finiscono qui cercando il messaggio di errore: La risposta di questa domanda simile mi ha aiutato a risolvere il problema abbastanza facilmente http://stackoverflow.com/a/18657986/4961688 –

risposta

118

Purtroppo qualsiasi DataGridColumn ospitato in DataGrid.Columns non fa parte dell'albero Visual e pertanto non è connesso al contesto dati del datagrid. Quindi i binding non funzionano con le loro proprietà come Visibility o Header ecc (sebbene queste proprietà siano proprietà di dipendenza valide!).

Ora potresti chiedermi come è possibile? La loro proprietà Binding non deve essere associata al contesto dati? Beh, è ​​semplicemente un hack. L'associazione non funziona davvero. In realtà sono le celle Datagrid che copia/clone questo oggetto vincolante e lo usa per visualizzare i propri contenuti!

Quindi ora di nuovo a risolvere il problema, presumo che HeaderItems sia una proprietà dell'oggetto impostata come DataContext della vista principale. Noi è possibile collegare il DataContext della vista a qualsiasi DataGridColumn tramite qualcosa che chiamiamo un ProxyElement.

L'esempio seguente mostra come collegare un bambino logica come ad esempio ContextMenu o DataGridColumn al genitore di vista DataContext

<Window x:Class="WpfApplicationMultiThreading.Window5" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
     xmlns:vb="http://schemas.microsoft.com/wpf/2008/toolkit" 
     Title="Window5" Height="300" Width="300" > 
    <Grid x:Name="MyGrid"> 
    <Grid.Resources> 
     <FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/> 
    </Grid.Resources> 
    <Grid.DataContext> 
     <TextBlock Text="Text Column Header" Tag="Tag Columne Header"/> 
    </Grid.DataContext> 
    <ContentControl Visibility="Collapsed" 
      Content="{StaticResource ProxyElement}"/> 
    <vb:DataGrid AutoGenerateColumns="False" x:Name="MyDataGrid"> 
     <vb:DataGrid.ItemsSource> 
      <x:Array Type="{x:Type TextBlock}"> 
       <TextBlock Text="1" Tag="1.1"/> 
       <TextBlock Text="2" Tag="1.2"/> 
       <TextBlock Text="3" Tag="2.1"/> 
       <TextBlock Text="4" Tag="2.2"/> 
      </x:Array> 
     </vb:DataGrid.ItemsSource> 
     <vb:DataGrid.Columns> 
      <vb:DataGridTextColumn 
         Header="{Binding DataContext.Text, 
            Source={StaticResource ProxyElement}}" 
         Binding="{Binding Text}"/> 
      <vb:DataGridTextColumn 
         Header="{Binding DataContext.Tag, 
            Source={StaticResource ProxyElement}}" 
         Binding="{Binding Tag}"/> 
     </vb:DataGrid.Columns> 
    </vb:DataGrid> 
    </Grid> 
</Window> 

La vista sopra incontrato lo stesso errore di legame che avete trovato se non hanno attuato la ProxyElement hack. ProxyElement è qualsiasi FrameworkElement che ruba il DataContext dalla vista principale e lo offre al figlio logico come ContextMenu o DataGridColumn. Per questo deve essere ospitato come Content in un invisibile ContentControl che si trova sotto la stessa vista.

Spero che questo ti guidi nella direzione corretta.

+17

Trovo che debba usare questo proxy hacky veramente deludente ma non riesco a trovare un altro modo per ottenere la stessa funzionalità altrimenti ... Grazie. –

+2

Questo non ha funzionato per me ma dopo aver letto l'articolo di Josh Smith sui rami virtuali ho provato ad aggiungere il binding OneWayToSource sul mio controllo root per impostare DataContext "ProxyElement" e questo ha funzionato. – jpierson

+0

@jpierson, stai usando 'Silverlight'? Coz funziona per me in 'WPF'. Per Silverlight l'implementazione è diversa. –

Problemi correlati