Error de WPF: no se puede encontrar el FrameworkElement gobernante para el elemento de destino

Resuelto KDP asked hace 13 años • 3 respuestas

Tengo DataGriduna fila que tiene una imagen. Esta imagen está vinculada con un disparador a un estado determinado. Cuando el estado cambia quiero cambiar la imagen.

La plantilla en sí está configurada en la HeaderStylebase de un archivo DataGridTemplateColumn. Esta plantilla tiene algunas vinculaciones. El primer día vinculante muestra qué día es y el estado cambia la imagen con un disparador.

Estas propiedades se establecen en un ViewModel.

Propiedades:

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,
    });
}

Cuadrícula de datos:

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

Plantilla de estilo de encabezado de cuadrícula de datos:

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

Ahora, cuando inicio el proyecto, las imágenes no se muestran y aparece este error:

Error System.Windows.Data: 2: No se puede encontrar el FrameworkElement o FrameworkContentElement que rige para el elemento de destino. BindingExpression:Path=HeaderItems[0]; Elemento de datos=nulo; el elemento de destino es 'DataGridTemplateColumn' (HashCode=26950454); la propiedad de destino es 'Encabezado' (escriba 'Objeto')

¿Por qué aparece este error?

KDP avatar Oct 05 '11 19:10 KDP
Aceptado

Lamentablemente, cualquier DataGridColumnalojamiento alojado DataGrid.Columnsen él no forma parte del Visualárbol y, por lo tanto, no está conectado al contexto de datos de la cuadrícula de datos. Por lo tanto, los enlaces no funcionan con sus propiedades como Visibilityo Headeretc (¡aunque estas propiedades son propiedades de dependencia válidas!).

Ahora te preguntarás ¿cómo es eso posible? ¿ No se Bindingsupone que su propiedad está vinculada al contexto de datos? Bueno, simplemente es un truco. La encuadernación realmente no funciona. En realidad, son las celdas de la cuadrícula de datos las que copian / clonan este objeto vinculante y lo utilizan para mostrar su propio contenido.

Ahora, volviendo a resolver su problema, supongo que HeaderItemses una propiedad del objeto que está configurada como de DataContextsu Vista principal. Podemos conectar la DataContextvista a cualquiera DataGridColumna través de algo que llamamos ProxyElement.

El siguiente ejemplo ilustra cómo conectar un hijo lógico como ContextMenuo DataGridColumna la vista principal.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 anterior encontró el mismo error vinculante que encontró si no hubiera implementado el truco ProxyElement. ProxyElement es cualquier FrameworkElement que roba de DataContextla Vista principal y se lo ofrece al hijo lógico como ContextMenuo DataGridColumn. Para eso, debe estar alojado como Contentun invisible ContentControlque se encuentra bajo la misma Vista.

Espero que esto te guíe en la dirección correcta.

Vinit Sankhe avatar Oct 05 '2011 13:10 Vinit Sankhe

Una alternativa ligeramente más corta al uso de a StaticResourcecomo en la respuesta aceptada es x:Reference:

<StackPanel>

    <!--Set the DataContext here if you do not want to inherit the parent one-->
    <FrameworkElement x:Name="ProxyElement" Visibility="Collapsed"/>

    <DataGrid>
        <DataGrid.Columns>
            <DataGridTextColumn
                Header="{Binding DataContext.Whatever, Source={x:Reference ProxyElement}}"
                Binding="{Binding ...}" />
        </DataGrid.Columns>
    </DataGrid>

</StackPanel>

La principal ventaja de esto es: si ya tiene un elemento que no es el ancestro de DataGrid (es decir, no el StackPaneldel ejemplo anterior), puede simplemente darle un nombre y usarlo como su x:Referencelugar, por lo que no es necesario definir ningún elemento ficticio. FrameworkElementen absoluto.

Si intenta hacer referencia a un antepasado, obtendrá un XamlParseExceptionerror en tiempo de ejecución debido a una dependencia cíclica.

FernAndr avatar Apr 10 '2020 09:04 FernAndr