Expander-like WPF control that only hides empty children

118 views Asked by At

In my WPF view, I need something similar to an Expander or a TreeView, but instead of completely hiding the content, I only want to hide empty parts, i.e. TextBoxes with null or empty text, or empty ItemCollections.

I thought about using a style with a DataTrigger or set Visibility with a converter, but how would I link that to the parent's setting (e.g. IsExpanded)? I would like to avoid doing this in the ViewModel, as that would need a property for each section (and I need lots of them), but it's purely visual and therefore IMHO it only belongs to the View.

So I guess the way to go is to use DependencyProperties or write some CustomControls, but I don't have an idea where to start. The XAML of the end result could look something like this:

<CustomExpander Header="Main" CollapseContentIfEmpty="True">
    <CustomExpander Header="Section1" CollapseContentIfEmpty="True">
        <StackPanel>
            <TextBox Text="{Binding SomeString}" />
            <TextBox Text="{Binding SomeEmptyString}" />
        </StackPanel>
    </CustomExpander>
    <CustomExpander Header="Section2" CollapseContentIfEmpty="True">
        <ListView ItemsSource="{Binding SomeCollectionView}" />
    </CustomExpander>
</CustomExpander>

In this example, if CollapseContentIfEmpty is set to true and the CollectionView shows no elements (e.g. due to filters), only the content of SomeString should be visible, along with all the headers. If SomeString is empty, only "Main" should be visible, as now all child CustomExpanders are empty as well.

Setting CollapseContentIfEmpty to false (e.g. via a Button like in Expander) would show all Children again, regardless if they are empty or not.

1

There are 1 answers

0
mm8 On

I thought about using a style with a DataTrigger or set Visibility with a converter, but how would I link that to the parent's setting (e.g. IsExpanded)?

Use a binding with a {RelativeSource}.

In the following example, the TextBlock is invisible unless you set the Tag property of the parent UserControl to true:

<UserControl xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <UserControl.Tag>
        <sys:Boolean>false</sys:Boolean>
    </UserControl.Tag>
    <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </UserControl.Resources>
    <StackPanel>
        <TextBlock Text="text..."
                   Visibility="{Binding Tag,
                     RelativeSource={RelativeSource AncestorType=UserControl}, 
                     Converter={StaticResource BooleanToVisibilityConverter}}" />
    </StackPanel>
</UserControl>

You can of course replace the UserControl with a custom control with a custom bool property.

An Expander collapses its entire Content which is different from hiding specific controls in that content.