如果内容被折叠,则折叠ContentControl

时间:2012-10-03 10:43:31

标签: wpf xaml binding datatemplate

我有一个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>

DecorativeItem类只是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')

我明白为什么会发生这种情况,但不知道如何根据我的需要修改我的风格。如果需要,我不介意向DecorativeItem子类添加辅助代码。知道如何解决这个问题吗?

[编辑1]

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

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

[编辑2]

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

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

1 个答案:

答案 0 :(得分:0)

有几种方法可以描述什么是错的。在第一个工作示例中:

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

ContentControl的Content属性设置为TextBlock,它是具有Visibility属性的UIElement。 (这假设您没有将派生类的ContentProtem的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属性。换句话说,DataTemplate生成生成内容的语句不正确 - 您的DataTemplate只是告诉控件如何显示String类型的内容。

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

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

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

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

  • 最后,您可以向TextBlock添加额外的DataTrigger。此DataTrigger将根据其自身的可见性设置其父级的可见性。然后,使用Path“Visibility”而不是“Content.Visibility”绑定StyleItem1样式中的DataTrigger,实际上是手动链接Visibilities。

修改

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