Hide Expander ToggleButton if no child items in WPF

牧云@^-^@ 提交于 2019-12-06 14:36:07

I have designed Two template for expander WithToggleButton and WithoutToggleButton.

  <Window.Resources>
    <ControlTemplate x:Key="WithToggleButton" TargetType="{x:Type Expander}">
         <!--Copy from msdn link as there is limitation to add code in stackoverflow-->
    </ControlTemplate>
    <ControlTemplate x:Key="WithoutToggleButton" TargetType="{x:Type Expander}">
        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="True">
            <DockPanel>
                <ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
                    <ToggleButton.Style>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Border Padding="{TemplateBinding Padding}">
                                            <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="1" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ToggleButton.Style>
                </ToggleButton>
                <ContentPresenter x:Name="ExpandSite" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" DockPanel.Dock="Bottom" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </DockPanel>
        </Border>
    </ControlTemplate>
</Window.Resources>
<StackPanel>
    <Expander Header="ExpanderWithoutContent" x:Name="Expander">
        <Expander.Style>
            <Style TargetType="Expander">
                <Setter Property="Template" Value="{StaticResource WithToggleButton}"/>
                <Style.Triggers>                        
                    <DataTrigger Binding="{Binding Path=Content,ElementName=Expander}" Value="{x:Null}">
                        <Setter Property="Template" Value="{StaticResource WithoutToggleButton}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Expander.Style>          
    </Expander>
    <Expander x:Name="Expander1" Header="ExpanderWithContent" >
        <Expander.Style>
            <Style TargetType="Expander">
                <Setter Property="Template" Value="{StaticResource WithToggleButton}"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=Content,ElementName=Expander1}" Value="{x:Null}">
                        <Setter Property="Template" Value="{StaticResource WithoutToggleButton}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Expander.Style>
        <Expander.Content>
            <Grid Height="50" Background="Green">
                <TextBlock Text="expander content" Foreground="White" FontSize="20" VerticalAlignment="Center"></TextBlock>                
            </Grid>
        </Expander.Content>
    </Expander>       
</StackPanel>

Result

Upadte

Plesae Add above expander template WithToggleButton and WithoutToggleButton in your existing window resource and replace your grid with below new xaml code.

 <Grid >
    <ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="10" Background="White">
        <Grid>
            <Label Name="lblstatus" HorizontalAlignment="center" VerticalAlignment="top" Margin="10" FontSize="14" FontWeight="bold" Foreground="Black" >Please wait...</Label>
            <ListBox  ItemsSource="{Binding}"  Name="TOCView"  ItemContainerStyle="{StaticResource ListBoxItemStyle}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Expander x:Name="Expander" ExpandDirection="Down" IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"  >
                            <Expander.Style>
                                <Style TargetType="Expander" BasedOn="{StaticResource ExpanderItemStyle}">
                                    <Setter Property="Template" Value="{StaticResource WithToggleButton}"/>
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Path=chapters}" Value="{x:Null}">
                                            <Setter Property="Template" Value="{StaticResource WithoutToggleButton}"/>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Expander.Style>
                            <Expander.Header> 
                                <BulletDecorator>
                                    <Button Tag="{Binding}"  Style="{StaticResource ResourceKey=BookPageStyle}" Click="MainChapterButton_Click"  Content="{Binding Path=name}"/>
                                </BulletDecorator>
                            </Expander.Header>
                            <Expander.Content>
                                <StackPanel>
                                    <ListBox x:Name="SubChapListBox" BorderThickness="0" Margin="20,0" ItemsSource="{Binding Path=chapters}"  ItemContainerStyle="{StaticResource ListBoxItemStyle}">
                                        <ListBox.ItemTemplate>
                                            <DataTemplate>
                                                <Expander Name="Expander1" ExpandDirection="Down"  BorderThickness="0">
                                                    <Expander.Style>
                                                        <Style TargetType="Expander" BasedOn="{StaticResource ExpanderItemStyle}">
                                                            <Setter Property="Template" Value="{StaticResource WithToggleButton}"/>
                                                            <Style.Triggers>
                                                                <DataTrigger Binding="{Binding Path=chapters}" Value="{x:Null}">
                                                                    <Setter Property="Template" Value="{StaticResource WithoutToggleButton}"/>
                                                                </DataTrigger>
                                                            </Style.Triggers>
                                                        </Style>
                                                    </Expander.Style>
                                                    <Expander.Header>
                                                        <BulletDecorator>
                                                            <Button Tag="{Binding}"  Style="{StaticResource ResourceKey=BookPageStyle}" Click="SubchpaterButton_Click"  Content="{Binding Path=name}"/>
                                                        </BulletDecorator>
                                                    </Expander.Header>
                                                    <StackPanel>
                                                        <ListBox x:Name="SubChapListBox" BorderThickness="0" Margin="20,0" ItemsSource="{Binding Path=chapters}"  ItemContainerStyle="{StaticResource ListBoxItemStyle}">
                                                            <ListBox.ItemTemplate>
                                                                <DataTemplate>
                                                                    <Expander Name="expander2" ExpandDirection="Down"  BorderThickness="0"  >
                                                                        <Expander.Style>
                                                                            <Style TargetType="Expander">
                                                                                <Setter Property="Template" Value="{StaticResource WithToggleButton}"/>
                                                                                <Style.Triggers>
                                                                                    <DataTrigger Binding="{Binding Path=chapters}" Value="{x:Null}">
                                                                                        <Setter Property="Template" Value="{StaticResource WithoutToggleButton}"/>
                                                                                    </DataTrigger>
                                                                                </Style.Triggers>
                                                                            </Style>
                                                                        </Expander.Style>
                                                                        <Expander.Header>
                                                                            <BulletDecorator>
                                                                                <Button Tag="{Binding}"  Style="{StaticResource ResourceKey=BookPageStyle}" Click="SubchpaterButton_Click"  Content="{Binding Path=name}"/>
                                                                            </BulletDecorator>
                                                                        </Expander.Header>
                                                                    </Expander>
                                                                </DataTemplate>
                                                            </ListBox.ItemTemplate>
                                                        </ListBox>
                                                    </StackPanel>
                                                </Expander>
                                            </DataTemplate>
                                        </ListBox.ItemTemplate>
                                    </ListBox>
                                </StackPanel>
                            </Expander.Content>
                        </Expander>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ListBox>
        </Grid>
    </ScrollViewer>
</Grid>

Result

Edit: As you want to Show the header you could define two different DataTemplates. In your xaml add a ContentControl:

 <ContentControl Content="{Binding YourViewModel}"
                 ContentTemplateSelector="{StaticResource YourDataTemplateSelector }" />

Also you would have to create a new DataTemplateSelector. The selector should return your DataTemplate for a Expander if your collection isnt empty and your template for e.g. TextBlock if your collection is empty.

public class YourDataTemplateSelector : DataTemplateSelector
{
    #region Properties

    public DataTemplate TextBoxTemplate
    {
        get;
        set;
    }

    public DataTemplate ExpanderTemplate
    {
        get;
        set;
    }

    public override Template SelectTemplate(object item, DependencyObject container)
    {
        // your logic do determine what template you need goes here

        if (...) {
            return TextBoxTemplate;
        } else if (...){
            return ExpanderTemplate;
        }
    }
}

And here is the xaml body for your datatemplates:

 <DataTemplateSelector x:Key="YourDataTemplateSelector"
                       TextBoxTemplate="{StaticResource ParameterTextBoxTemplate}"
                       ExpanderTemplate="{StaticResource ParameterExpanderTemplate}"/>

<DataTemplate x:Key="ParameterTextBoxTemplate">
    ...
</DataTemplate>
<DataTemplate x:Key="ParameterExpanderTemplate">
    ...
</DataTemplate>

You want to use the default BooleanToVisibilityConverter to bind to your ListBox. First you need to add a resource:

<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />

then you can bind to the HasItems Property of the ListBox

<Expander ExpandDirection="Down" 
          IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"
          Visibility="{Binding Path=HasItems, ElementName=SubChapListBox, Converter={StaticResource BooleanToVisibilityConverter}}">

edit: as correctly stated will this hide the complete expander including the header. But you can use the same Binding at the BulletDecorator (or the Button Content inside of it) instead:

<Expander.Header>
    <BulletDecorator Visibility="{Binding Path=HasItems, ElementName=SubChapListBox, Converter={StaticResource BooleanToVisibilityConverter}}">                                                                                
        <Button Tag="{Binding}"  Style="{StaticResource ResourceKey=BookPageStyle}" Click="MainChapterButton_Click"  Content="{Binding Path=name}" >
        </Button>
    </BulletDecorator>
</Expander.Header>
kxj

This is solution is for DataGrid grouping but same idea should work for ListView. Create two ControlTemplate as Resources.

<Window.Resources>
    <ControlTemplate x:Key="DataGridGroupExpender" TargetType="{x:Type GroupItem}">
        <Expander IsExpanded="True" Background="LightGray" BorderThickness="1,1,1,1">
            <Expander.Header>
                <DockPanel>
                    <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0"/>
                    <TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount, StringFormat=: {0}}"/>
                </DockPanel>
            </Expander.Header>
            <Expander.Content>
                <ItemsPresenter />
            </Expander.Content>
        </Expander>
    </ControlTemplate>
    <ControlTemplate x:Key="DataGridGroupNoExpender" TargetType="{x:Type GroupItem}">
        <ItemsPresenter />
    </ControlTemplate>
</Window.Resources>

Use DataTrigger to switch ContainerStyle based on number of items in the group: 1 means no child and therefor no Expander.

<GroupStyle>
    <GroupStyle.ContainerStyle>
        <Style TargetType="{x:Type GroupItem}">
            <Setter Property="Margin" Value="0,0,0,5"/>
            <Setter Property="Template"  Value="{StaticResource DataGridGroupExpender}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=ItemCount}" Value="1">
                    <Setter Property="Template" Value="{StaticResource DataGridGroupNoExpender}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </GroupStyle.ContainerStyle>
</GroupStyle>
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!