如何在WPF XAML中将ContentPresenter默认内容设置为未设置

时间:2019-06-04 20:02:49

标签: wpf xaml

我正在尝试在状态栏中显示状态图标。这些图标被定义为ViewBox静态资源,并通过ContentPresenter样式与DataTriggers一起显示。

如果不匹配任何触发器,我希望不显示任何图标,因此我尝试将默认的设置内容设置为x:Null或为空字符串或完全删除该行,但其他图标停止显示然后。

有什么想法吗?

我的XAML代码如下

<StatusBarItem Grid.Column="2">
    <ContentPresenter>
        <ContentPresenter.Style>
            <Style TargetType="ContentPresenter">
                <Setter Property="Content" Value="{x:Null}"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=State}" Value="Ok">
                        <Setter Property="Content" Value="{StaticResource StatusOK}"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=State}" Value="Invalid">
                        <Setter Property="Content" Value="{StaticResource StatusInvalid}"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=State}" Value="Warning">
                        <Setter Property="Content" Value="{StaticResource StatusWarning}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ContentPresenter.Style>
    </ContentPresenter>
</StatusBarItem>

更新

我曾尝试使用Ed Plunkett建议的可见性,但这些图标完全停止显示。这是代码。

<Style TargetType="ContentPresenter">
    <Setter Property="Content" Value="{StaticResource StatusOK}"/>
    <Setter Property="Visibility" Value="Collapsed"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=State}" Value="Ok">
            <Setter Property="Content" Value="{StaticResource StatusOK}"/>
            <Setter Property="Visibility" Value="Visible"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=State}" Value="Invalid">
            <Setter Property="Content" Value="{StaticResource StatusInvalid}"/>
            <Setter Property="Visibility" Value="Visible"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=State}" Value="Warning">
            <Setter Property="Content" Value="{StaticResource StatusWarning}"/>
            <Setter Property="Visibility" Value="Visible"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

1 个答案:

答案 0 :(得分:0)

您的问题是滥用ContentPresenter。没有理由在ControlTemplate之外使用ContentPresenter。它唯一与ContentControl不同的功能是仅在ControlTemplate内部有意义的事物。现在,StatusBarItemContentControl的子类,因此您可以设置StatusBarItem的样式并设置其Content。您问题中的任何一个版本都可以那样工作。

但是有一种更好,更强大的方法可以做到这一点:

<Window.Resources>
    <Ellipse x:Key="StatusOK" Fill="Green" Width="20" Height="20" x:Shared="False" />
    <Path 
        x:Key="StatusInvalid" 
        Fill="Red" 
        Width="20" 
        Height="20" 
        x:Shared="False"  
        Data="M 34.2,87.4 L 12.3,65.5 L 12.3,34.5 L 34.2,12.6 L 65.2,12.6 L 87.1,34.5 L 87.1,65.5 L 65.2,87.4 Z" 
        Stretch="Uniform" 
        />
    <Rectangle x:Key="StatusWarning" Fill="Orange" Width="20" Height="20" x:Shared="False" />

    <DataTemplate x:Key="StateDataTemplate">
        <ContentControl x:Name="Icon" Width="20" Height="20" />

        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding}" Value="Ok">
                <Setter TargetName="Icon" Property="Content" Value="{StaticResource StatusOK}"/>
                <Setter TargetName="Icon" Property="Visibility" Value="Visible"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding}" Value="Invalid">
                <Setter TargetName="Icon" Property="Content" Value="{StaticResource StatusInvalid}"/>
                <Setter TargetName="Icon" Property="Visibility" Value="Visible"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding}" Value="Warning">
                <Setter TargetName="Icon" Property="Content" Value="{StaticResource StatusWarning}"/>
                <Setter TargetName="Icon" Property="Visibility" Value="Visible"/>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>
</Window.Resources>

StatusBarItem:

<StatusBarItem 
    Grid.Column="2" 
    Content="{Binding State}" 
    ContentTemplate="{StaticResource StateDataTemplate}" 
    />
<StatusBarItem Grid.Column="3">
    <!--  
    This demonstrates how we can reuse the State datatemplate. My enum is named Status. 
    -->
    <ComboBox 
        SelectedItem="{Binding State}" 
        ItemTemplate="{StaticResource StateDataTemplate}" 
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        >
        <x:Null/>
        <local:Status>Ok</local:Status>
        <local:Status>Invalid</local:Status>
        <!-- Anything that stringifies as "Warning" works with the trigger -->
        <sys:String>Warning</sys:String>
    </ComboBox>
</StatusBarItem>

请注意,我在每个图标内容资源上都放置了x:Shared="False"。当我们这样做时,我们将能够在其他地方使用具有相同枚举类型的其他属性重用此DataTemplate。如果没有x:Shared,将只有一个“ Ok”状态为Ellipse,并且如果两个控件尝试使用它,则第二个控件将从第一个中窃取它。资源是其中包含图像的ViewBox还是Ellipse或其他内容都没有关系。只需将x:Shared放在上面。

还要注意DataTriggers中的Binding="{Binding}"。我们正在模板StatusBarItem的内容。这意味着绑定到Content的{​​{1}}属性的任何内容都是StatusBarItem内部的DataContext。这意味着我们可以将数据模板重用于绑定到具有其他名称的属性的其他控件,只要这些属性的类型相同(或相似;这将适用于任何字符串形式为“ Ok”,“ Invalid”的值) ,或“警告”)。 DataTemplate的意思是“不要绑定到DataContext的某些命名属性;只需绑定到DataContext对象本身”。在这种情况下,这就是枚举值。

默认情况下,我们不隐藏“图标”内容控件,因为在默认状态下,没有图标。我不知道您的{Binding}属性是否可以为空,或者是否存在第四种“无”状态。顺便说一句,没有“静态资源”之类的东西。资源就是资源。 StaticResource is a class that retrieves resources one way; DynamicResource retrieves them another way