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


87

我有一个DataGrid带有图像的行。该图像与触发器绑定到特定状态。当状态改变时,我想改变图像。

模板本身设置HeaderStyleDataGridTemplateColumn。该模板具有一些绑定。第一个具有约束力的“ Day”(日期)显示了它是星期几,“ State”(状态)通过触发器更改了图像。

这些属性在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:Path = HeaderItems [0]; DataItem = null; 目标元素是“ DataGridTemplateColumn”(HashCode = 26950454);目标属性为“标题”(类型为“对象”)

为什么显示此错误?


4
我检查了上面回答的解决方案,但在我的情况下不起作用。当我切换到链接thomaslevesque.com/2011/03/21/…中的另一个解决方案时。他们的想法与解决方案相同,他们没有使用FrameworkElement,而是创建了另一个类。然后它对我有用。
leo5th

对于其他通过搜索错误消息而到此结束的人:相似问题的答案帮助我相当轻松地解决了问题stackoverflow.com/a/18657986/4961688
Tim Pohlmann,

Answers:


165

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

现在您可能想知道这怎么可能?它们的Binding属性不应该绑定到数据上下文吗?好吧,这简直就是黑客。绑定实际上不起作用。实际上,是复制/克隆此绑定对象并将其用于显示其自身内容的datagrid单元!

现在回到解决您的问题,我假设HeaderItems这是设置DataContext为父视图的对象的属性。我们可以连接DataContext视图的任何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是,任何FrameworkElement的抢断DataContext从主视图,它提供的逻辑子如ContextMenuDataGridColumn。为此,必须将其托管为同一视图下的Content不可见ContentControl对象。

我希望这会指导您正确的方向。


25
我发现不得不使用这种骇人听闻的代理东西确实令人失望,但否则我找不到其他方法来实现相同的功能……谢谢。
Alex Hope O'Connor

2
这对我不起作用,但是在阅读了乔希·史密斯关于虚拟分支的文章之后,我尝试在根控件上添加OneWayToSource绑定以设置“ ProxyElement” DataContext,并且该方法有效。
jpierson 2012年

1
不。上面的解决方案非常适合.NET 3.5。
WPF-it

1
这个答案很旧,但对.NET 4.0仍然有用。关于将DataContext复制到该列的许多答案似乎都不起作用。我需要根据视图模型属性显示/隐藏列,此解决方案效果很好。并且没有任何代码遗留不会在代码审查中引起外交事件。
James_UK_DEV 2014年

3
FYI上下文菜单不同,并且具有非代理替代方法。上下文菜单具有暴露的属性,Parent而菜单DataGridTextColumn不暴露其DataGridOwner属性。怎么看上下文绑定的物品通过的RelativeSource我的回答结合来实现上下文菜单绑定到父窗口的DataContext的
ΩmegaMan

8

StaticResource在接受的答案中,使用a的简短替代方法是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>

这样做的主要好处是:如果你已经有这一个元素不是一个DataGrid的祖先(即StackPanel上面的例子),你可以给它一个名字,并把它作为x:Reference代替,因此不需要定义任何虚FrameworkElement完全没有

如果您尝试引用祖先,则XamlParseException由于周期性依赖关系,您将在运行时获得。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.