У меня есть DataGrid
строка с изображением. Это изображение привязано триггером к определенному состоянию. Когда состояние меняется, я хочу изменить изображение.
Сам шаблон устанавливается на HeaderStyle
из DataGridTemplateColumn
. У этого шаблона есть привязки. Первый день привязки показывает, какой сегодня день, а состояние меняет изображение с помощью триггера.
Эти свойства устанавливаются в ViewModel.
Свойства:
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 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>
Теперь, когда я запускаю проект, изображения не отображаются, и я получаю эту ошибку:
System.Windows.Data Ошибка: 2: не удается найти управляющий FrameworkElement или FrameworkContentElement для целевого элемента. BindingExpression: Путь = HeaderItems [0]; DataItem = null; целевой элемент - DataGridTemplateColumn (HashCode = 26950454); целевое свойство - "Заголовок" (тип "Объект")
Почему отображается эта ошибка?
Ответы:
К сожалению, все, что
DataGridColumn
находится подDataGrid.Columns
ним, не является частьюVisual
дерева и, следовательно, не связано с контекстом данных datagrid. Таким образом, привязки не работают со своими свойствами, такими какVisibility
или иHeader
т.д. (хотя эти свойства являются действительными свойствами зависимости!).Теперь вы можете задаться вопросом, как это возможно? Разве их
Binding
собственность не должна быть привязана к контексту данных? Ну это просто взлом. Привязка толком не работает. На самом деле именно ячейки сетки данных копируют / клонируют этот объект привязки и используют его для отображения своего содержимого!Итак, теперь вернемся к решению вашей проблемы, я предполагаю, что
HeaderItems
это свойство объекта, установленного в качествеDataContext
родительского представления. Мы можем связатьDataContext
представление с любым сDataGridColumn
помощью того, что мы называем aProxyElement
.В приведенном ниже примере показано, как подключить логический дочерний элемент, например,
ContextMenu
илиDataGridColumn
к родительскому View.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>
Представление выше обнаружило ту же ошибку привязки, которую вы обнаружили, если бы я не реализовал взлом ProxyElement. ProxyElement любое FrameworkElement , который крадет
DataContext
от главного View и предлагает ее логического ребенка , такие какContextMenu
илиDataGridColumn
. Для этого он должен быть размещен как объект-Content
невидимка,ContentControl
находящийся под тем же представлением.Надеюсь, это приведет вас в правильном направлении.
источник
Parent
тогда какDataGridTextColumn
не раскрывает егоDataGridOwner
свойство. Посмотрите, как выполняется привязка элементов контекста через привязку RelativeSource в моем ответе « Привязка контекстного меню к тексту данных родительского окна»Немного более короткая альтернатива использованию
StaticResource
as в принятом ответе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>
Главное преимущество этого: если у вас уже есть элемент , который не предок сетки данных (т.е. не
StackPanel
в примере выше), вы можете просто дать ему имя и использовать его какx:Reference
вместо того, чтобы , следовательно , не нуждаясь определить любую пустышкуFrameworkElement
совсем.Если вы попытаетесь сослаться на предка, вы получите
XamlParseException
во время выполнения из-за циклической зависимости.источник