我有一个带有图像的Row的数据网格。此图像与某个状态的触发器绑定。当状态改变时我想改变图像。
模板本身在DataGridTemplateColumn的HeaderStyle上设置。此模板具有一些绑定。第一个绑定日显示它是什么日期,状态通过触发器更改图像。
这些属性在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:
<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; target元素是'DataGridTemplateColumn'(HashCode = 26950454); target属性是'Header'(类型'Object')
为什么会显示此错误?
答案 0 :(得分:140)
可悲的是,DataGridColumn
下托管的DataGrid.Columns
不属于Visual
树的一部分,因此未连接到数据网格的数据上下文。因此绑定不适用于Visibility
或Header
等属性(尽管这些属性是有效的依赖属性!)。
现在你可能想知道这怎么可能?是不是他们的Binding
属性应该绑定到数据上下文?嗯它只是一个黑客。绑定并不真正起作用。它实际上是复制 / 克隆这个绑定对象的数据网格单元格,并用它来显示自己的内容!
现在回到解决您的问题,我假设HeaderItems
是对象的属性,设置为父视图的DataContext
。我们可以通过我们称为 DataContext
的内容1}}将视图DataGridColumn
连接到任何ProxyElement
。
以下示例说明了如何将ContextMenu
或DataGridColumn
这样的逻辑子项连接到父视图的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 hack,上面的视图遇到了你发现的相同绑定错误。 ProxyElement是来自主视图的窃取 DataContext
的任何FrameworkElement,并将其提供给逻辑子项,例如ContextMenu
或DataGridColumn
。为此,它必须作为Content
托管到同一视图下的不可见ContentControl
。
我希望这能指导你正确的方向。
答案 1 :(得分:8)
在接受的答案中,使用StaticResource
的一种替代方法是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>
这样做的主要优点是:如果您已经拥有一个 not 不是DataGrid祖先的元素(即,在上面的示例中, not StackPanel
) ,您可以给它起一个名称并将其用作x:Reference
,因此根本不需要定义任何虚拟FrameworkElement
。
如果您尝试引用祖先,由于周期性的依赖性,您将在运行时获得XamlParseException
。
答案 2 :(得分:0)
没有代理的方式是在构造函数中设置绑定:
var i = 0;
var converter = new BooleanToVisibilityConverter();
foreach(var column in DataGrid.Columns)
{
BindingOperations.SetBinding(column, DataGridColumn.VisibilityProperty, new Binding($"Columns[{i++}].IsSelected")
{
Source = ViewModel,
Converter = converter,
});
}