-2

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
  • Seems complicated to generalize this into a control. Speculating, I think you would need a custom control derived from expander. Also a consistent way to identify if each child of the expander are "empty" according to your criteria, (so probably an attached property, much like Grid.Row/Grid.Column ). And you would need to rely on the children to set it. Likewise when a child changed from empty to non-empty (or vice versa) you'd need some sort of bubbling event to go from the children to the parent. The parent could then check all children for the attached "empty" and adjust.
    – Joe
    Commented Apr 21, 2022 at 2:08

1 Answer 1

-1

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.