Search code examples
wpfxamlgridgrid-layoutdockpanel

WPF: DockPanel Last Visible Child Fill?


The behavior I'm looking for is basically that of a DockPanel, I would like the last child to fill the available space. The catch is that I would like it to be the last visible child. In my case I have two views I would like to display side by side.

So far I have tried applying two different styles to a grid, neither seems to work. I also tried using a converter which seemed to work in theory(I was able to return "Auto" using double.NaN), but I wasn't sure how to return a width of "*" from code.

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*">
            <ColumnDefinition.Style>
                <Style TargetType="{x:Type ColumnDefinition}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Visibility, ElementName=ccSomeItems}" Value="Collapsed">
                            <Setter Property="Width" Value="0" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ColumnDefinition.Style>
        </ColumnDefinition>
        <ColumnDefinition Width="*">
            <ColumnDefinition.Style>
                <Style TargetType="{x:Type ColumnDefinition}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding SomeOtherItems.AllOtherItems.Count, Converter={StaticResource IntegerToVisibilityConverter}}" Value="Collapsed">
                            <Setter Property="Width" Value="0" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ColumnDefinition.Style>
        </ColumnDefinition>
    </Grid.ColumnDefinitions>
    <ContentControl x:Name="ccSomeItems" Content="{Binding SomeItems}" Margin="4" Visibility="{Binding SomeItems.AllItems.Count, Converter={StaticResource IntegerToVisibilityConverter}}" />
    <ContentControl Grid.Column="1" Content="{Binding SomeOtherItems}" Margin="4" Visibility="{Binding SomeOtherItems.AllOtherItems.Count, Converter={StaticResource IntegerToVisibilityConverter}}" />
</Grid>

Solution

  • I was able to run with Rachel's comment and find a solution using a converter.

    XAML:

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="{Binding Visibility, ElementName=SomeItems, Converter={StaticResource VisibilityToGridLengthConverter}}" />
            <ColumnDefinition Width="{Binding Visibility, ElementName=SomeOtherItems, Converter={StaticResource VisibilityToGridLengthConverter}}" />
        </Grid.ColumnDefinitions>
        <ContentControl x:Name="SomeItems" Content="{Binding SomeItems}" Visibility="{Binding SubPackages.AllPackages.Count, Converter={StaticResource IntegerToVisibilityConverter}}" />
        <ContentControl x:Name="SomeOtherItems" Grid.Column="1" Content="{Binding SomeOtherItems}" Visibility="{Binding Elements.AllElements.Count, Converter={StaticResource IntegerToVisibilityConverter}}" />
    </Grid>
    

    And the Converter:

    [ValueConversion(typeof(Visibility), typeof(GridLength))]
    public class VisibilityToGridLengthConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (Visibility)value == Visibility.Collapsed ? new GridLength(0) : new GridLength(1, GridUnitType.Star);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }