是否可以绑定到装饰元素容器上的属性?
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 RelativeSource
和 AncestorType
,这是一个很棒的链接:
http://druss.co/2013/10/wpf-binding-examples/
看看你是否能理解 WPF 中的可视树和逻辑树是如何工作的,一旦你理解了这一点,你就会更多地了解绑定是如何工作的。
我还建议使用免费工具Snoop
查看可视化树。 XAML Spy
很棒,但不是免费的。
Snoop
可以告诉您在运行时是否有任何绑定错误(您设置了过滤器,它会列出所有错误绑定)。
您可以使用Snoop
获取源的完整 XAML 路径(您在上面编写的 XAML),然后获取目标的完整 XAML 路径(即您的 Grid
的 ActualWidth
),然后进行比较它们:可能很快就会发现一个不是另一个的祖先,因为它们位于视觉树的不同分支上,或者还有其他问题阻止了简单地向上遍历视觉树。
如果您只是想让某些东西正常工作,作为概念证明,请尝试使用 x:Name
命名目标 XAML 网格,并通过名称而不是 AncestorType
引用它。
【讨论】:
虽然这是一些很棒的信息,但我并没有真正看到它是如何具体解决我的问题的;也许只是因为我的问题不够清楚。命名网格并不是一个真正的选择,因为模板是一种共享资源,可以在应用程序的任何地方使用,因此它需要更通用。我已经使用 snoop 来调查对象图,并且有问题的 Textblock 不属于网格的范围,至少不是直接的。我将添加一些屏幕截图来演示这一点。 刚刚添加了有关如何使用 Snoop 来诊断问题的信息。 另外要明确的是,虽然不是专家,但我通常很喜欢使用 RelativeSource 和 AncestorType。我在这里的阻碍是试图获得兄弟姐妹的祖先,而不是正常的直接祖先。 @Phaeze 我明白了。你能不能试着把树走到祖先那里,然后走到合适的兄弟姐妹那里? 我不能这样做,因为我不知道要向上或向后遍历多少层,无论在可视树中的哪个位置使用此模板,它都需要能够工作。我已经能够回答编辑中澄清的问题之一;看起来 adornedElementPlaceholder 不提供对装饰元素的祖先的访问。以上是关于是否可以绑定到装饰元素容器上的属性?的主要内容,如果未能解决你的问题,请参考以下文章
Flex 警告:无法绑定到类“Object”上的属性“foo”(类不是 IEventDispatcher)
WebService 之 已超过传入消息(65536)的最大消息大小配额。若要增加配额,请使用相应绑定元素上的 MaxReceivedMessageSize 属性。