是否可以绑定到装饰元素容器上的属性?

Posted

技术标签:

【中文标题】是否可以绑定到装饰元素容器上的属性?【英文标题】:Is it possible to bind to a property on the container of the Adorned Element? 【发布时间】:2015-05-25 19:27:42 【问题描述】:

在我的 WPF 应用程序中,我们使用装饰器来显示验证消息,在特定情况下,有一个具有多个控件的单行网格,其中一些控件具有验证。我遇到的问题是我想强制错误消息控件的宽度与网格相同,但似乎无法找到从装饰模板中引用该网格的方法。这是我尝试过的示例:

<ControlTemplate x:Key="Local_TopAdornedTemplateWide">
    <StackPanel>
        <AdornedElementPlaceholder x:Name="adornedElement"/>
        <TextBlock MaxWidth="Binding Path=ActualWidth, RelativeSource=RelativeSource FindAncestor, AncestorType=Grid, ElementName=adornedElement"
                   TextWrapping="Wrap"
                   Text="Binding Converter=StaticResource Local_ValidationErrorMessageConverter" 
                   Style="DynamicResource Error_Text" 
                   Padding="2 1 0 0" 
                   Visibility="Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter=StaticResource BooleanToVisibilityConverter"
                   />
    </StackPanel>
</ControlTemplate>

这会导致应用程序崩溃并出现 XamlParseException。

理想情况下,解决方案不会特定于网格,以便获得任何容器类型的宽度,但目前网格是唯一的用例。

编辑: 这是我们在应用程序中使用的另一个模板的示例;此模板不适用于我的情况,因为它将错误限制为上述网格的单列的宽度:

 <ControlTemplate x:Key="Local_TopAdornedErrorTemplate">
        <StackPanel>
            <AdornedElementPlaceholder x:Name="adornedElement"/>
            <TextBlock MaxWidth="Binding ElementName=adornedElement, Path=ActualWidth"
                       TextWrapping="Wrap"
                       Text="Binding Converter=StaticResource Local_ValidationErrorMessageConverter" 
                       Style="DynamicResource Error_Text" 
                       Padding="2 1 0 0" 
                       Visibility="Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter=StaticResource BooleanToVisibilityConverter"
                       />
        </StackPanel>
    </ControlTemplate>

使用 snoop 我捕获了以下两个屏幕截图(我无法获取完整堆栈中的一个以防止发布任何专有内容)

这张照片显示了我之前提到的网格,其中是正在装饰的 FinancialTextBox 项

这个镜头展示了两件事,蓝色选中的项目是上一个镜头中网格的最高祖先,黄色突出显示的是内容模板中的文本框

对于这两个,似乎很明显(根据 Contango 的回答中的信息)这两个项目不在同一个视觉树中,这会让我相信我的问题是不可能的。然而,我添加的第二个模板(确实有效)指出,来自装饰元素的至少一些视觉信息存在于占位符中。

所以现在我的问题归结为 a)这些信息是否包括被装饰元素的父元素,以及 b)如何通过对不同元素的绑定来访问它?

【问题讨论】:

【参考方案1】:

这比我试图走的路要简单得多。

我在阅读 AdornedElementPlaceholder 类时遇到了this entry on MSDN,并注意到该类实际上有一个名为 parent 的属性,我尝试了以下绑定,它运行良好:

MaxWidth="Binding ElementName=adornedElement, 
                   Mode=OneWay, 
                   Path=AdornedElement.Parent.ActualWidth"

【讨论】:

【参考方案2】:

WPF 非常强大和灵活。

您可以将任何 XAML 标记中的任何属性绑定到任何其他 XAML 标记中的任何属性。

例如,您可以编写一个测试应用程序,将输入框的Text 属性绑定到标签的Text 属性,这样当您在文本框中输入内容时,标签会自动更改(假设你使用UpdateSourceTrigger=PropertyChanged)。这是直接的 XAML 到 XAML 绑定,看不到 C#。

同样,您可以将错误框的宽度绑定到父控件的宽度,无论它是什么。

Google RelativeSourceAncestorType,这是一个很棒的链接:

http://druss.co/2013/10/wpf-binding-examples/

看看你是否能理解 WPF 中的可视树和逻辑树是如何工作的,一旦你理解了这一点,你就会更多地了解绑定是如何工作的。

我还建议使用免费工具Snoop 查看可视化树。 XAML Spy 很棒,但不是免费的。

Snoop 可以告诉您在运行时是否有任何绑定错误(您设置了过滤器,它会列出所有错误绑定)。

您可以使用Snoop 获取源的完整 XAML 路径(您在上面编写的 XAML),然后获取目标的完整 XAML 路径(即您的 GridActualWidth),然后进行比较它们:可能很快就会发现一个不是另一个的祖先,因为它们位于视觉树的不同分支上,或者还有其他问题阻止了简单地向上遍历视觉树。

如果您只是想让某些东西正常工作,作为概念证明,请尝试使用 x:Name 命名目标 XAML 网格,并通过名称而不是 AncestorType 引用它。

【讨论】:

虽然这是一些很棒的信息,但我并没有真正看到它是如何具体解决我的问题的;也许只是因为我的问题不够清楚。命名网格并不是一个真正的选择,因为模板是一种共享资源,可以在应用程序的任何地方使用,因此它需要更通用。我已经使用 snoop 来调查对象图,并且有问题的 Textblock 不属于网格的范围,至少不是直接的。我将添加一些屏幕截图来演示这一点。 刚刚添加了有关如何使用 Snoop 来诊断问题的信息。 另外要明确的是,虽然不是专家,但我通常很喜欢使用 RelativeSource 和 AncestorType。我在这里的阻碍是试图获得兄弟姐妹的祖先,而不是正常的直接祖先。 @Phaeze 我明白了。你能不能试着把树走到祖先那里,然后走到合适的兄弟姐妹那里? 我不能这样做,因为我不知道要向上或向后遍历多少层,无论在可视树中的哪个位置使用此模板,它都需要能够工作。我已经能够回答编辑中澄清的问题之一;看起来 adornedElementPlaceholder 不提供对装饰元素的祖先的访问。

以上是关于是否可以绑定到装饰元素容器上的属性?的主要内容,如果未能解决你的问题,请参考以下文章

Flex 警告:无法绑定到类“Object”上的属性“foo”(类不是 IEventDispatcher)

Python - 三大器 迭代器,生层器,装饰器

WebService 之 已超过传入消息(65536)的最大消息大小配额。若要增加配额,请使用相应绑定元素上的 MaxReceivedMessageSize 属性。

flex布局

JavaFx 元素未绑定到 fx:id 上的控制器变量 [重复]

弹性盒子