WPF错误:找不到目标元素的管理FrameworkElement

时间:2011-10-05 12:00:57

标签: wpf image binding datagrid multidatatrigger

我有一个带有图像的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')

为什么会显示此错误?

3 个答案:

答案 0 :(得分:140)

可悲的是,DataGridColumn下托管的DataGrid.Columns不属于Visual树的一部分,因此未连接到数据网格的数据上下文。因此绑定不适用于VisibilityHeader等属性(尽管这些属性是有效的依赖属性!)。

现在你可能想知道这怎么可能?是不是他们的Binding属性应该绑定到数据上下文?嗯它只是一个黑客。绑定并不真正起作用。它实际上是复制 / 克隆这个绑定对象的数据网格单元格,并用它来显示自己的内容!

现在回到解决您的问题,我假设HeaderItems是对象的属性,设置为父视图的DataContext。我们可以通过我们称为 DataContext 的内容DataGridColumn连接到任何ProxyElement

以下示例说明了如何将ContextMenuDataGridColumn这样的逻辑子项连接到父视图的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,并将其提供给逻辑子项,例如ContextMenuDataGridColumn。为此,它必须作为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,
    });
}