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

时间:2015-05-25 19:27:43

标签: c# wpf xaml

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

<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项目

Adorned item

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

Adorner

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

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

2 个答案:

答案 0 :(得分:4)

这最终比我想要的路径简单得多。

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

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

答案 1 :(得分:-2)

WPF非常强大且灵活。

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

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

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

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

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

看看你是否可以了解Visual Tree和Logical Tree在WPF中是如何工作的,一旦你理解了这一点,你就会更加了解绑定是如何工作的。

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

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

您可以使用Snoop获取源的完整XAML路径(您在上面编写的XAML),然后获取目标的完整XAML路径(即{{1} ActualWidth然后比较它们:很快就会发现一个人不是另一个人的祖先,因为他们在视觉树的不同分支上,或者还有一些其他问题阻碍了视觉上的简单行走工作中的树。

如果您只想获得一些有用的功能,作为概念验证,请尝试使用Grid命名目标XAML网格,并按名称而不是x:Name引用它。