1

In a WPF Project I have a Grid defined with two rows each containing a ListBox. The RowDefinitions have their Height = '*' so equal space is allocated to each ListBox. What I would like to happen however, is that when either ListBox is not fully needing all its own space (through items being removed at runtime) then that 'spare' space is given over to the other ListBox.

So, using the code I list below, both ListBox's start off with equal space which is correct. Pressing the button deletes some entries from the top ListBox (topList), resulting in white space below the remaining 2 entries. It's this space I would like to be granted to the bottom ListBox. And vice versa.

XAML:

<Window x:Class="FiftyPercentSplit.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:FiftyPercentSplit"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid Height="200">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
   </Grid.RowDefinitions>

    <Button x:Name="btnDeleteFromTopList" Click="btnDeleteFromTopList_Click" Content="Delete from Top List"/>

    <ListBox  x:Name="topList" Grid.Row="1">
        <ListBoxItem>1</ListBoxItem>
        <ListBoxItem>2</ListBoxItem>
        <ListBoxItem>3</ListBoxItem>
        <ListBoxItem>4</ListBoxItem>
        <ListBoxItem>5</ListBoxItem>
        <ListBoxItem>6</ListBoxItem>
        <ListBoxItem>7</ListBoxItem>
        <ListBoxItem>8</ListBoxItem>
        <ListBoxItem>9</ListBoxItem>
    </ListBox>

    <ListBox  x:Name="bottomList" Grid.Row="2">
        <ListBoxItem>1</ListBoxItem>
        <ListBoxItem>2</ListBoxItem>
        <ListBoxItem>3</ListBoxItem>
        <ListBoxItem>4</ListBoxItem>
        <ListBoxItem>5</ListBoxItem>
        <ListBoxItem>6</ListBoxItem>
        <ListBoxItem>7</ListBoxItem>
        <ListBoxItem>8</ListBoxItem>
        <ListBoxItem>9</ListBoxItem>
    </ListBox>

</Grid>
</Window>

Code behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void btnDeleteFromTopList_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 0; i < 7; i++)
        {
            topList.Items.RemoveAt(0);
        }
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Cleve
  • 1,273
  • 1
  • 13
  • 26
  • And if you subsequently remove items from the bottom list, everything should revert back to equal sizes? That's hardly possible without some code behind magic. – Clemens Mar 06 '17 at 17:22
  • @Cleve, did you try the approach I suggested in my answer? Does it work for you? – ASh Mar 13 '17 at 07:42
  • Hi @ASh, so sorry for not replying sooner. Yes I did try it and it worked great. Really liked the 'Measurer' trick. Thanks! – Cleve Mar 13 '17 at 11:11

2 Answers2

1

Just use StackPanel instead of Grid like this:

    <Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<StackPanel Height="200">

    <Button x:Name="btnDeleteFromTopList" Click="btnDeleteFromTopList_Click" Content="Delete from Top List"/>

    <ListBox  x:Name="topList" Grid.Row="1">
        <ListBoxItem>1</ListBoxItem>
        <ListBoxItem>2</ListBoxItem>
        <ListBoxItem>3</ListBoxItem>
        <ListBoxItem>4</ListBoxItem>
        <ListBoxItem>5</ListBoxItem>
        <ListBoxItem>6</ListBoxItem>
        <ListBoxItem>7</ListBoxItem>
        <ListBoxItem>8</ListBoxItem>
        <ListBoxItem>9</ListBoxItem>
    </ListBox>

    <ListBox  x:Name="bottomList" Grid.Row="2">
        <ListBoxItem>1</ListBoxItem>
        <ListBoxItem>2</ListBoxItem>
        <ListBoxItem>3</ListBoxItem>
        <ListBoxItem>4</ListBoxItem>
        <ListBoxItem>5</ListBoxItem>
        <ListBoxItem>6</ListBoxItem>
        <ListBoxItem>7</ListBoxItem>
        <ListBoxItem>8</ListBoxItem>
        <ListBoxItem>9</ListBoxItem>
    </ListBox>

</StackPanel>

S.Cheginy
  • 424
  • 2
  • 15
1

effectively the 2nd row should behave as Auto-height row. But scrollable controls like ListBox don't work well in Auto-height row - they grow infinitely and don't show scroll. To overcome it I usually have to set MaxHeight.

In this case I left 2 RowDefinitions with Height="*", used element with name Measurer to get actual height of the rows and set the MaxHeight for topList from ActualHeight of Measurer. Note also that I used a nested Grid with <RowDefinition Height="Auto"/>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Button x:Name="btnDeleteFromTopList" Click="btnDeleteFromTopList_Click" Content="Del"/>

    <Border Grid.Row="2" Name="Measurer"/>

    <Grid Grid.Row="1" Grid.RowSpan="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <ListBox  Grid.Row="0" x:Name="topList" VerticalAlignment="Top"
                  MaxHeight="{Binding ActualHeight, ElementName=Measurer}">

        </ListBox>

        <ListBox  x:Name="bottomList" Grid.Row="1">

        </ListBox>
    </Grid>       
</Grid>
  • ListBoxItems removed from the sample to avoid code clutter in the answer
ASh
  • 34,632
  • 9
  • 60
  • 82