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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7660967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:06:41  来源:igfitidea点击:

WPF Error: Cannot find governing FrameworkElement for target element

wpfimagebindingdatagridmultidatatrigger

提问by KDP

I've got a DataGridwith a row that has an image. This image is bound with a trigger to a certain state. When the state changes I want to change the image.

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

The template itself is set on the HeaderStyleof a DataGridTemplateColumn. This template has some bindings. The first binding Day shows what day it is and the State changes the image with a trigger.

模板本身设置在 的HeaderStyleDataGridTemplateColumn。这个模板有一些绑定。第一个绑定日显示它是哪一天,状态会通过触发器更改图像。

These properties are set in a ViewModel.

这些属性在 ViewModel 中设置。

Properties:

特性:

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>

Now when I startup the project the images doesn't show and I get this error:

现在,当我启动项目时,图像不显示,并且出现此错误:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=HeaderItems[0]; DataItem=null; target element is 'DataGridTemplateColumn' (HashCode=26950454); target property is 'Header' (type 'Object')

System.Windows.Data 错误:2:找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement。BindingExpression:Path=HeaderItems[0]; 数据项=空;目标元素是“DataGridTemplateColumn”(HashCode=26950454);目标属性是“标题”(类型“对象”)

Why is this error showing?

为什么会显示这个错误?

回答by WPF-it

Sadly any DataGridColumnhosted under DataGrid.Columnsis not part of Visualtree and therefore not connected to the data context of the datagrid. So bindings do not work with their properties such as Visibilityor Headeretc (although these properties are valid dependency properties!).

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

Now you may wonder how is that possible? Isn't their Bindingproperty supposed to be bound to the data context? Well it simply is a hack. The binding does not really work. It is actually the datagrid cells that copy/ clonethis binding object and use it for displaying their own contents!

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

So now back to solving your issue, I assume that HeaderItemsis a property of the object that is set as the DataContextof your parent View. We canconnect the DataContextof the view to any DataGridColumnvia something we call a ProxyElement.

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

The example below illustrates how to connect a logical child such as ContextMenuor DataGridColumnto the parent View's DataContext

下面的示例说明了如何将逻辑子项(例如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>

The view above encountered the same binding error that you have found if I did not have implemented the ProxyElement hack. The ProxyElement is any FrameworkElement that stealsthe DataContextfrom the main View and offers it to the logical child such as ContextMenuor DataGridColumn. For that it must be hosted as a Contentinto an invisible ContentControlwhich is under the same View.

如果我没有实现 ProxyElement hack,上面的视图遇到了相同的绑定错误。该ProxyElement是,任何FrameworkElement的抢断DataContext从主视图,它提供的逻辑子如ContextMenuDataGridColumn。为此,它必须作为一个Content隐藏ContentControl在同一个视图下的无形中托管。

I hope this guides you in correct direction.

我希望这能引导您朝着正确的方向前进。

回答by FernAndr

A slightly shorter alternative to using a StaticResourceas in the accepted answer is x:Reference:

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>

The main advantage of this is: if you already have an element which is nota DataGrid's ancestor (i.e. notthe StackPanelin the example above), you can just give it a name and use it as the x:Referenceinstead, hence not needing to define any dummy FrameworkElementat all.

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

If you try referencing an ancestor, you will get a XamlParseExceptionat run-time due to a cyclical dependency.

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