能否绑定到装饰元素容器上的属性?(涉及IT技术)

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

4
这比我之前尝试的方法简单多了。我在阅读AdornedElementPlaceholder类的相关资料时,发现 MSDN上的这篇文章 中提到该类实际上有一个名为parent的属性。于是我尝试了以下绑定方式,结果完美运行:
MaxWidth="{Binding ElementName=adornedElement, 
                   Mode=OneWay, 
                   Path=AdornedElement.Parent.ActualWidth}"

-1

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 路径,然后获取目标(即你的 GridActualWidth)的完整 XAML 路径,然后进行比较:很快就会发现它们不是彼此的祖先,因为它们在可视树的不同分支上,或者存在其他问题阻止了简单地沿着可视树向上走。

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


虽然这是一些很棒的信息,但我并没有看到它如何具体解决我的问题;也许只是因为我的问题不够清晰。给网格命名并不是一个真正的选项,因为该模板是一个共享资源,可以在应用程序的任何地方使用,所以它需要更加通用。我已经使用 Snoop 来调查对象图,并且所涉及的 Textblock 并不直接属于该网格的范围之内。我将添加一些截图来证明这一点。 - user1618236
刚刚添加了如何使用Snoop诊断问题的信息。 - Contango
还有需要明确的是,虽然我不是专家,但我通常对使用RelativeSource和AncestorType感到非常舒适。我的难点在于尝试获取兄弟节点的祖先,而不是像通常那样获取直接祖先。 - user1618236
@Phaeze 我明白了。你能尝试将树向上遍历到祖先,然后再向下遍历到适当的兄弟节点吗? - Contango
所以,既然这个问题得到了解答,我今天稍后会尝试一些东西,将StackPanel替换为一个不提供无限宽度的面板,这应该会隐式地给我我想要的结果。 - user1618236
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接