DiscreteObjectKeyFrame

DiscreteObjectKeyFrame

本文介绍了Tag属性中的WPF数据绑定错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:son"
         x:Class="son.SonWindow">
    <Grid x:Name="myGrid">
        <Grid.Tag>
            <Label Content="{Binding ActualWidth, ElementName=myGrid}" />
        </Grid.Tag>
    </Grid>
</UserControl>

上面只是一个简单的代码,但是绑定找不到Element myGrid。在运行时,错误显示在输出窗口中

Just as a simple code above, but the binding cannot find the Element myGrid. During runtime, the error is shown in the Output window

我正在使用Visual Studio 2015社区版本.Net Framework 4.5.2。有任何想法吗?谢谢你提前。

I am using Visual Studio 2015 community version with .Net Framework 4.5.2. Any ideas? Thank you in advance.

推荐答案

元素(其属性是约束的)应该是视觉树的一部分,以便视觉树搜索可以完成。当使用带有 ElementName RelativeSource 的绑定时,它执行一些内部视觉树搜索。但是在您的代码中,标签与视觉树通过标签断开连接。 标签只是内存中的一个对象,由Tag属性引用。

The element (whose property is bound) should be part of the visual tree so that the visual tree search can be done. When using Binding with ElementName or RelativeSource, it performs some internal visual tree search. But in your code the Label is disconnected from visual tree by the Tag. Label is just an object in memory, referenced by the Tag property.

由于.NET 4.0,您可以使用 {x:Reference} 标记,如下所示:

Since .NET 4.0 you can use the {x:Reference} markup instead, like this:

<Grid.Tag>
    <Label Content="{Binding ActualWidth, Source={x:Reference myGrid}}" />
</Grid.Tag>

修改

使用 {x:Reference} 可能导致循环依赖性问题,如果引用名称指向包含 {x:Reference} 。在你的情况下,它是 myGrid (包含 {x:Reference} )。所以它不能用于你的情况。相反,您需要使用一些代理。这种技术似乎有点黑客,但实际上它很漂亮。它也可以在任何版本的.NET(支持WPF)中工作:

Using {x:Reference} can cause issue of cyclic dependency if the reference name points to some element containing the {x:Reference}. In your case it is myGrid (containing {x:Reference}). So it cannot be used in your case. Instead you need to use some proxy. This technique seems a bit hacky but in fact it's very pretty. It also surely works in any version of .NET (supporting WPF):

<Grid x:Name="myGrid">
    <Grid.Resources>
        <DiscreteObjectKeyFrame x:Key="proxy" Value="{Binding ElementName=myGrid}"/>
    </Grid.Resources>
    <Grid.Tag>
        <Label Content="{Binding Value.ActualWidth, Source={StaticResource proxy}}" />
    </Grid.Tag>
</Grid>

正如您看到的Binding与其来源设置为 StaticResource 指向 DiscreteObjectKeyFrame 。这是一个 Freezable 对象,所以非常有趣的是,对于 Freezable 对象的任何DependencyProperty设置的所有Bindings都很好,无论如何您使用 ElementName RelativeSource 。因此,我们将属性绑定到 Grid (名称为 myGrid )。稍后,我们将内容属性标签绑定到 Freezable 对象,但使用路径设置为 Value.ActualWidth 指向 Grid ,所以我们需要添加 ActualWidth 将其绑定到 Grid.ActualWidth )。

As you see the Binding works with its Source set to StaticResource pointing to a DiscreteObjectKeyFrame. This is a Freezable object so it's quite interesting that all Bindings set for any DependencyProperty of a Freezable object work well no matter you use ElementName or RelativeSource. So we bind its Value property to the Grid (with name of myGrid). Later on we bind the Content property of Label to the Freezable object but with Path set to Value.ActualWidth (Value points to Grid, so we need to append ActualWidth to bind it to Grid.ActualWidth).

其实你可以使用任何 Freezable 对象,但是我们使用 DiscreteObjectKeyFrame 为方便起见,其接受各种对象

In fact you can use any Freezable object but we use DiscreteObjectKeyFrame for convenience, its Value accepts all kinds of object.

还有一种技术可以在这种情况下设置Binding(断开的上下文),但它需要您创建一个自定义的 MarkupExtension 。这当然更复杂(但是一旦你熟悉WPF,就会很简单)。

There is another technique to set Binding in a situation like this (disconnected context) but it requires you to create a custom MarkupExtension. It's of course more complicated (but still simple enough once you're familiar with WPF).

这篇关于Tag属性中的WPF数据绑定错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 07:12