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

C# 是否可以绑定到装饰元素容器上的属性?,c#,wpf,xaml,C#,Wpf,Xaml,在我的WPF应用程序中,我们使用一个装饰器来显示验证消息,在特定情况下,有一个单行网格具有多个控件,其中一些控件具有验证。我遇到的问题是,我想强制错误消息控件的宽度与网格相同,但似乎找不到从装饰器模板引用该网格的方法。以下是我尝试的示例: <ControlTemplate x:Key="Local_TopAdornedTemplateWide"> <StackPanel> <AdornedElementPlaceholder x:Name="

在我的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)如何通过不同元素上的绑定来访问这些信息?

WPF非常强大和灵活

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

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

类似地,您可以将错误框的宽度绑定到父控件的宽度,不管是什么

Google
RelativeSource
AncestorType
,这是一个很好的链接:

看看你是否可以探索一下可视化树和逻辑树在WPF中是如何工作的,一旦你理解了这一点,你就会对绑定的工作原理有更多的了解

我还建议使用免费工具
Snoop
查看可视化树<代码>XAML Spy非常出色,但不是免费的

Snoop
可以告诉您在运行时是否有任何绑定不正确的内容(您设置了过滤器,它将列出所有不正确的绑定)

您可以使用
Snoop
获取源的完整XAML路径(您在上面编写的XAML),然后获取目标的完整XAML路径(即
网格的
实际宽度
),然后比较它们:很快就会发现其中一个不是另一个的祖先,因为它们位于可视化树的不同分支上,或者,还有其他一些问题阻碍了在可视化树上进行简单的漫游


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

,这比我尝试的路径简单得多

我在阅读AdorneDeletePlaceholder类时,偶然发现该类实际上有一个名为parent的属性,因此我尝试了以下绑定,它工作得非常完美:

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

虽然这是一些很好的信息,但我不知道它是如何具体解决我的问题的;也许这只是因为我的问题不够清楚。命名网格实际上不是一个选项,因为模板是一个共享资源,可以在应用程序中的任何位置使用,所以它需要更通用。我已经使用snoop调查了对象图,所讨论的文本块不在网格范围内,至少不直接在网格范围内。我将添加一些屏幕截图来演示这一点。只是添加了有关如何使用Snoop来识别问题的信息。同样要明确的是,虽然不是专家,但我通常对使用RelativeSource和AncestorType非常满意。我的拦截器在这里试图得到一个兄弟姐妹的祖先,而不是一个正常的直系祖先。@Phaeze我理解。您可以尝试将树向上移动到祖先,然后向下移动到相应的兄弟节点吗?同样,我不能这样做,因为我不知道要向上或向下移动多少层,此模板需要能够工作,无论它在可视化树中的何处使用。我已经能够回答编辑中澄清的一个问题;看起来AdorneDeletePlaceholder不提供对装饰元素的祖先的访问。