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

Posted

技术标签:

【中文标题】WPF 错误:找不到目标元素的管理 FrameworkElement【英文标题】:WPF Error: Cannot find governing FrameworkElement for target element 【发布时间】:2021-08-22 05:50:33 【问题描述】:

我有一个DataGrid,其中一行有一张图片。此图像通过触发器绑定到某个状态。当状态改变时,我想改变图像。

模板本身设置在DataGridTemplateColumnHeaderStyle 上。这个模板有一些绑定。第一个绑定 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>

数据网格 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];数据项=空;目标元素是“DataGridTemplateColumn”(HashCode=26950454);目标属性是“标题”(类型“对象”)

为什么会出现这个错误?

【问题讨论】:

我检查了上面回答的解决方案,但它不适用于我的情况。当我切换到链接thomaslevesque.com/2011/03/21/… 中的另一个解决方案时。这个想法和解决方案一样,他们没有使用FrameworkElement,而是创建了另一个类。然后它对我有用。 对于其他人通过搜索错误消息最终到达这里:这个类似问题的答案帮助我相当容易地解决了问题***.com/a/18657986/4961688 【参考方案1】:

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

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

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

下面的示例说明了如何将逻辑子级(例如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 并将其提供给逻辑子视图(例如ContextMenuDataGridColumn)的FrameworkElement。为此,它必须作为 Content 托管到同一视图下的不可见 ContentControl 中。

我希望这会引导你正确的方向。

【讨论】:

我发现不得不使用这个 hacky 代理的东西真的很令人失望,但我找不到其他方法来实现相同的功能......谢谢。 这对我不起作用,但在阅读了 Josh Smith 关于虚拟分支的文章后,我尝试在我的根控件上添加 OneWayToSource 绑定以设置“ProxyElement”DataContext,并且效果很好。 不。上面的解决方案非常适合 .NET 3.5。 这个答案很旧,但对 .NET 4.0 仍然有用。涉及将 DataContext 复制到列的许多答案似乎都不起作用。我需要根据视图模型属性显示/隐藏列,并且此解决方案运行良好。并且没有代码后面不会导致代码审查中的外交事件。 仅供参考上下文菜单不一样,并且有一个非代理解决方法。上下文菜单有一个公开的属性Parent,而DataGridTextColumn 没有公开它的DataGridOwner 属性。在我的回答 Context Menu Binding to Parent Window's Datacontext 中查看如何通过 RelativeSource 绑定来完成上下文项绑定【参考方案2】:

在接受的答案中使用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>

这样做的主要优点是:如果您已经有一个元素不是 DataGrid 的祖先(即不是上面示例中的StackPanel),您可以只给它一个名称并将其用作x:Reference,因此根本不需要定义任何虚拟FrameworkElement

如果您尝试引用祖先,由于循环依赖,您将在运行时获得XamlParseException

【讨论】:

有趣,谢谢!想知道为什么我们必须经历这个麻烦 这会产生运行时错误DataContext property not found on object of type Reference.【参考方案3】:

没有代理的方法是在构造函数中设置绑定:

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,
    );

【讨论】:

以上是关于WPF 错误:找不到目标元素的管理 FrameworkElement的主要内容,如果未能解决你的问题,请参考以下文章

WPF datagrid.rowstyle 绑定

WPF 样式中的绑定导致莫名其妙的“找不到管理 FrameworkElement”错误

WPF 自定义 DatagridColumn 绑定问题

找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement。渐变停止

我该如何解决这个“找不到对象!” CodeIgniter-4 中的错误?

为啥,致命错误:在...中找不到类“PHPUnit_Framework_TestCase”?