Reputation: 174457
Consider the following XAML:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="100" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox>
<ListBox.Items>
<ListBoxItem>a</ListBoxItem>
<!-- Another 11 items -->
</ListBox.Items>
</ListBox>
<ListBox Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.Items>
<ListBoxItem>1</ListBoxItem>
<!-- Another 23 items -->
</ListBox.Items>
</ListBox>
</Grid>
</Window>
The ListBox in the second row shows the vertical scrollbar as disabled and simply cuts off the content.
I want it to be constrained to the visible area of the window. How to achieve this?
Rational behind setting the height of the second grid row to Auto: I want the second ListBox to display all its content without a scrollbar if there is enough space for it and the first ListBox should take the remaining space.
Upvotes: 0
Views: 592
Reputation: 2368
I don't think there's any way to do what you want in pure XAML - you have to set a specific height for one or other of the two listboxes, or set fixed proportions for them.
I think you could do what you want with a bit of code in the code behind. Give your RowDefinitions and Listboxes names, as follows, and subscribe to the GridSizedChanged event:
<Grid SizeChanged="GridSizeChanged">
<Grid.RowDefinitions>
<RowDefinition x:Name="row1"/>
<RowDefinition x:Name="row2"/>
</Grid.RowDefinitions>
<ListBox x:Name="lb1">
<ListBox.Items>
<ListBoxItem>a</ListBoxItem>
</ListBox.Items>
</ListBox>
<ListBox x:Name="lb2" Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.Items>
<ListBoxItem>1</ListBoxItem>
<!-- Another 23 items -->
</ListBox.Items>
</ListBox>
</Grid>
Then handle the event in the following way:
private void GridSizeChanged(object sender, SizeChangedEventArgs e)
{
double newHeight = e.NewSize.Height;
int lb1ItemCount = lb1.Items.Count;
int lb2ItemCount = lb2.Items.Count;
row1.Height = new GridLength(newHeight * lb1ItemCount / (lb1ItemCount + lb2ItemCount));
row2.Height = new GridLength(newHeight * lb2ItemCount / (lb1ItemCount + lb2ItemCount));
}
This sets the size of the two listboxes to be proportional to the number of items they have inside them. If you want to set a minimum size of 100 for the first listbox, you'll have to do a bit more work to set that size first, then base the second size off the calculated value for the first size.
Edit: I think I've written a version of GridSizeChanged that does exactly what you require. This version will set the height of lb2 to either the whole grid except the top 100px (if the desired listbox size is bigger than this), or just to its own desired size if that is smaller. The first listbox will then fill all remaining space, and will have a minimum height of 100px as you require, because we did not allow lb2 to fill the top 100px.
private void GridSizeChanged(object sender, SizeChangedEventArgs e)
{
lb2.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
double lb2DesiredHeight = lb2.DesiredSize.Height;
double newHeight = e.NewSize.Height;
double lb2AvailableHeight = newHeight - 100;
double lb2ActualHeight = Math.Min(lb2DesiredHeight, lb2AvailableHeight);
row1.Height = new GridLength(newHeight - lb2ActualHeight);
row2.Height = new GridLength(lb2ActualHeight);
}
Upvotes: 1