1

我有一个 ContentControl,它的样式包含边框和其他视觉装饰。我希望这些装饰在内容折叠时消失,所以我想在这种情况下我必须将 ContentControl 的可见性设置为折叠。我的 ContentControl 装饰采用了这种风格:

<Style x:Key="DecoratedItem1" TargetType="{x:Type c:DecoratedItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type c:DecoratedItem}">
                <StackPanel Orientation="Horizontal">
                    <Border BorderBrush="Black" BorderThickness="2" CornerRadius="2">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="/Images/file.png"/>
                            <ContentPresenter Name="wContent"/>
                        </StackPanel>
                    </Border>
                </StackPanel>
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding ElementName=wContent, Path=Content.Visibility}" Value="Collapsed">
                        <DataTrigger.Setters>
                            <Setter Property="Visibility" Value="Collapsed"/>
                        </DataTrigger.Setters>
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

DecoratedItem 类只是 ContentControl 的子类,带有与此问题无关的附加 DependencyProperties,我只想指出,我已经有一个子类,如果需要,我可以向其中添加代码。

这在 ContentControl 的内容是 UIElement 时有效,但是如果内容是由 DataTemplate 生成的,它会抱怨无法找到 Visibility 属性。

<!-- works -->
<c:DecoratedItem Style="{StaticResource DecoratedItem1}">
    <TextBlock Text="ABC" Visibility="Collapsed"/>
</c:DecoratedItem>

<!-- doesn't work -->
<c:DecoratedItem Style="{StaticResource DecoratedItem1}" Content="ABC">
    <c:DecoratedItem.Resources>
        <DataTemplate DataType="{x:Type clr:String}">
            <TextBlock Text="{Binding}" Visibility="Collapsed"/>
        </DataTemplate>
    </c:DecoratedItem.Resources>
</c:DecoratedItem>

调试输出窗口中显示的第二种情况的错误是:

System.Windows.Data Error: 40 : BindingExpression path error:
'Visibility' property not found on 'object' ''String' (HashCode=-885832486)'.
BindingExpression:Path=Content.Visibility;
DataItem='ContentPresenter' (Name='wContent');
target element is 'DecoratedItem' (Name='');
target property is 'NoTarget' (type 'Object')

我理解为什么会发生这种情况,但不知道如何修复我的风格以按照我的意愿工作。如有必要,我不介意将帮助代码添加到 DecoratedItem 子类。知道如何解决这个问题吗?

[编辑 1]

关于提议的答案的更多解释:

我不能强制 Content 始终是 UIElement。毕竟这是一个模型视图设计,当然我简化了很多例子。在实际项目中,内容是从 DataContext 中选择的一个模型,它可以是几种不同的类型,DataTemplate 为该模型构建一个表示。一些 DataTemplates 决定(取决于模型状态)没有任何东西可以呈现并将 Visibility 切换为 Collapsed。我想将该信息传播到装饰容器。上面的例子真的只是提出了问题而不是动机,对不起。

[编辑 2]

不知道更多地了解该模型将如何帮助解决问题,但我们开始吧。Content 字段中的数据没有太多共同点,因为它可以是很多东西,这个 DecoratedItem 应该是可重用的,以便为某些表单上显示的项目提供通用的视觉样式。内容可以是工作项之类的东西,如果它们被禁用,则 DataTemplate 会折叠它们;其他类型的内容可能不完整并被折叠。当然,其他种类永远不会崩溃。

但是请注意,数据模型与问题并没有太大关系,这仍然是如何绑定扩展内容元素的可见性(在可能以可绑定方式通过子类公开它之后)。

4

1 回答 1

0

有几种方法可以描述问题所在。在第一个工作示例中:

<c:DecoratedItem Style="{StaticResource DecoratedItem1}">
    <TextBlock Text="ABC" Visibility="Collapsed"/>
</c:DecoratedItem>

ContentControl 的 Content 属性设置为 TextBlock,它是具有 Visibility 属性的 UIElement。(这假设您没有将派生类 DecoratedItem 的 ContentPropertyAttribute 更改为 Content 以外的内容)。因此,您的 DataTrigger 绑定可以正确评估:

 <DataTrigger Binding="{Binding ElementName=wContent, Path=Content.Visibility}" Value="Collapsed">

将工作案例与失败案例进行对比:

<c:DecoratedItem Style="{StaticResource DecoratedItem1}" Content="ABC">

其中 Content 属性设置为 String 的实例,该实例没有 Visibility 属性。

描述问题的另一种方法是注意,即使您为 Content 是 String 的情况提供 DataTemplate,Content 仍然是 String 并且仍然没有 Visibility 属性。换句话说,Content由 DataTemplate生成的说法是不正确的——您的 DataTemplate 只是告诉控件如何显示 String 类型的 Content。

您的问题的一般答案是,如果您希望 DecoratedItem1 中的 DataTrigger 与 Content.Visibility 的路径绑定,您需要确保放入其中的内容始终是 UIElement。相反,如果您希望能够将任何类型的内容放入控件中,则需要触发其他内容。

严格来说,您的问题的具体答案取决于您更广泛的意图(特别是如何设置/修改控件内容的可见性)。几种可能性:

  • 如果您真的想要表单的 DataTrigger 绑定“Content.Visibility”,请确保 Content 始终是 UIElement。例如,使用样式的工作形式,然后将 TextBlock 的 Text 绑定到适当的东西。但是,这不太适合将派生控件作为 ContentControl 的想法,所以...

  • 您的 DataTrigger 可能会绑定到其他东西。从问题的形成方式来看,似乎还有一些其他属性或代码隐藏将控制各种内容实体是否可见。

  • 最后,您可以向 TextBlock 添加一个额外的 DataTrigger。此 DataTrigger 将根据其自身的可见性设置其父级的可见性。然后,将样式 DecoratedItem1 中的 DataTrigger 与路径“Visibility”而不是“Content.Visibility”绑定,本质上是手动将 Visibilities 链接在一起。

编辑

根据您对如何使用它的描述,听起来您需要考虑可视化树。您可以将 DecoratedItem 控件扩充为具有以下功能:如果其所有作为 UIElments 的可视子项都具有 Collapsed 的可见性(或者如果它没有可视子项),那么它也是 Collapsed(或者,任何对所需功能有意义的逻辑就其视觉子项的可见性而言)。您需要从代码中使用VisualTreeHelper类——特别是 GetChildrenCount 和 GetChild 方法。您还可以在 DecoratedItem 类中覆盖 OnVisualChildrenChanged(同时仍调用基类方法),以便您可以获取可见子项的 UIElement.IsVisibleChanged 事件。

于 2012-10-03T17:03:00.710 回答