tengo un DataGrid con una fila que tiene una imagen. Esta imagen está vinculada con un disparador a un cierto estado. Cuando el estado cambia, quiero cambiar la imagen.
La propia plantilla se establece en el HeaderStyle de a DataGridTemplateColumn. Esta plantilla tiene algunos enlaces. 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>
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>
Ahora, cuando inicio el proyecto, las imágenes no se muestran y aparece este error:
Error de System.Windows.Data: 2: No se puede encontrar FrameworkElement o FrameworkContentElement para el elemento de destino. BindingExpression: Path = HeaderItems [0]; DataItem = null; el elemento de destino es 'DataGridTemplateColumn' (HashCode = 26950454); la propiedad de destino es 'Encabezado' (tipo 'Objeto')
¿Por qué se muestra este error?

Respuestas:
Lamentablemente, cualquier
DataGridColumnalojado debajoDataGrid.Columnsno es parte delVisualárbol y, por lo tanto, no está conectado al contexto de datos de la cuadrícula de datos. Así que las fijaciones no trabajan con sus propiedades, tales comoVisibilityoHeaderetc (aunque estas propiedades son las propiedades de dependencia válidos!).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 unión no funciona realmente. En realidad, son las celdas de la cuadrícula de datos las que copian / clonan este objeto de enlace y lo usan para mostrar su propio contenido.Entonces, volviendo a resolver su problema, supongo que
HeaderItemses una propiedad del objeto que se establece como laDataContextVista principal. Nos podemos conectar elDataContextde la vista para cualquierDataGridColumnmedio de algo que llamamos unaProxyElement.El siguiente ejemplo ilustra cómo conectar un hijo lógico como
ContextMenuoDataGridColumncon la vista principalDataContext<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 de enlace que ha encontrado si no implementé el truco ProxyElement. El ProxyElement es cualquier FrameworkElement que roba el
DataContextde la Vista principal y lo ofrece al hijo lógico comoContextMenuoDataGridColumn. Para eso debe ser alojado como unContenten un invisibleContentControlque está bajo la misma Vista.Espero que esto le oriente en la dirección correcta.
fuente
Parentmientras que elDataGridTextColumnno expone suDataGridOwnerpropiedad. Vea cómo se logra un enlace de elementos de contexto a través del enlace RelativeSource en mi respuesta Enlace del menú contextual al contexto de datos de la ventana principalUna alternativa un poco más corta a usar
StaticResourcecomo en la respuesta aceptada esx: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 un ancestro de DataGrid (es decir, no es el
StackPaneldel ejemplo anterior), puede simplemente darle un nombre y usarlo como elx:Referenceen su lugar, por lo tanto, no necesita definir ningún ficticioFrameworkElementen absoluto.Si intenta hacer referencia a un antepasado, obtendrá un
XamlParseExceptionen tiempo de ejecución debido a una dependencia cíclica.fuente