I'm new to WPF/XAML and with a few hours I got a GUI that is presentable except for one thing. I got the controls to resize horizontally with the window but I cannot figure out what I'm missing to do the same vertically. I want only the DataGrid control to stretch vertically. The Datagrid control is not getting the hint. What am I missing?
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MinHeight="480"
MinWidth="660"
Width="660"
Height="480"
Title="Windows Title">
<Grid Margin="0,0,-0.2,0.2">
<StackPanel Orientation="Vertical">
<DataGrid
x:Name="dataGrid"
Width="Auto"
Height="Auto"
MinHeight="300"
Grid.Row="0"
HorizontalAlignment="Stretch"
Margin="10,10,10,0"
VerticalAlignment="Stretch"
IsReadOnly="True"
TextBlock.FontSize="16"/>
<TextBox
x:Name="Interpretation"
Height="100"
MinHeight="100"
Width="Auto"
HorizontalAlignment="Stretch"
Margin="10,10,10,0"
IsReadOnly="True"
Text="Interpretation of Results"
TextAlignment="left"
TextBlock.FontSize="20"
TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</Window>
SOLUTION with ADDED controls and comments
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="600"
MinHeight="600"
MinWidth="660"
Width="660"
Title="Windows Title">
<Grid>
<Grid.RowDefinitions>
<!-- Height="Auto" -> Fill space required by content -->
<!-- Height="*" -> Fill all space not taken up by other rows (The one that will stretch) -->
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- using HorizontalAlignment="Stretch" or Width="Auto" in the controls is redundant -->
<!-- Don't forget to add Grid.Row="#" properties in each control/row below -->
<TextBox
MinHeight="25"
Grid.Row="0"
HorizontalAlignment="Stretch"
Margin="10,10,10,0"
Background="#FF98D6EB"
Foreground="White"
IsReadOnly="True"
Text="Results"
TextAlignment="Center"
TextBlock.FontSize="20"
TextWrapping="Wrap"/>
<DataGrid
x:Name="dataGrid"
MinHeight="200"
Grid.Row="1"
Margin="10,10,10,0"
IsReadOnly="True"
TextBlock.FontSize="16"/>
<TextBox
x:Name="Interpretation"
MinHeight="100"
Grid.Row="2"
Margin="10,10,10,0"
Background="#FF98D6EB"
IsReadOnly="True"
Text="Interpretation of Results"
TextAlignment="left"
TextBlock.FontSize="20"
TextWrapping="Wrap"/>
<!-- UniformGrid speads the buttons size evenly with resizing of the window -->
<!-- HorizontalAlignment="Stretch" is redundant -->
<!-- notice the Grid.Row="3" is a property of <UniformGrid> and not the controls within it-->
<UniformGrid
Height="100"
Grid.Row="3"
Columns="2"
Rows="1">
<Button
Name="btnContinue"
MinWidth="250"
Margin="10"
Content="Continue"
TextBlock.FontSize="50"
TextBlock.FontWeight="Bold"/>
<Button
Name="btnCancel"
MinWidth="250"
Margin="10"
Content="Cancel"
TextBlock.FontSize="50"
TextBlock.FontWeight="Bold"/>
</UniformGrid>
</Grid>
</Window>
A Grid will expand to fill its parent. You can use the root level grid in your window, if you won't be adding any more content.
To put two controls in a grid one above the other, define rows, and don't neglect to add the Grid.Row="..." attribute to the child controls to determine which grid rows they'll be in, or else they'll be superimposed on one another.
<Grid Margin="0,0,-0.2,0.2">
<Grid.RowDefinitions>
<!-- Height="*" -> Fill all space not taken up by other rows -->
<RowDefinition Height="*" />
<!-- Height="Auto" -> Fill space required by content -->
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DataGrid
Grid.Row="0"
x:Name="dataGrid"
Margin="10,10,10,0"
IsReadOnly="True"
TextBlock.FontSize="16"
/>
<TextBox
Grid.Row="1"
x:Name="Interpretation"
Height="100"
MinHeight="100"
Margin="10,10,10,0"
IsReadOnly="True"
Text="Interpretation of Results"
TextAlignment="left"
TextBlock.FontSize="20"
TextWrapping="Wrap"
/>
</Grid>
If you've got a series of auto-sized children that'll be adjacent, it can be simpler to make one row a StackPanel:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DataGrid
Grid.Row="0"
...
/>
<StackPanel
Grid.Row="1"
Orientation="Vertical"
>
<Label>Stuff</Label>
<TextBox ... />
<Label>More Stuff</Label>
<TextBox ... />
</StackPanel>
</Grid>
You put it in a stackpanel.
Stackpanels only ever grow to the size their contents need, you should use Grid instead, grids and their cells will fill their container.
Related
I was working on a UserControl in a View, when I came across this problem:
I set my content grids row heights to be 2*, 1* and 1* with the lines in between set to auto.
Now. The uppermost row has a grid nested in with a TextBlock and a TextBox. The height of the cell is in no way 2*. It looks like it would look if I had set it to auto. I'm pretty sure the other 2 content rows (containing buttons) are the right height either.
Now I hope you guys can help me fix this. I've googled around a bit and I can't seem to find a fitting solution.
Here's the code:
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="TBCustomerTitle" Margin="0,0,8,0" FontWeight="Bold"
Visibility="{Binding SetVisibility, UpdateSourceTrigger=PropertyChanged}">Customer:</TextBlock>
<TextBox Name="TBCustomerData" Grid.Column="1"
Visibility="{Binding SetVisibility, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding DisplayedCustomer.Name, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Grid>
<Line Grid.Row="1" Style="{StaticResource horizontalLineStyle}" />
<StackPanel Grid.Row="2" Orientation="Vertical">
<Button Command="{Binding AddCommand}">Add a new customer</Button>
<Button Command="{Binding UpdateCommand}">Update the selected customer</Button>
<Button Command="{Binding DeleteCommand}">Delete the selected customer</Button>
</StackPanel>
<Line Grid.Row="3" Style="{StaticResource horizontalLineStyle}" />
<StackPanel Grid.Row="4" Orientation="Vertical">
<Button Command="{Binding RefreshCommand}">Refresh the list</Button>
<Button Command="{Binding ClearSelectionCommand}">Clear selection</Button>
</StackPanel>
</Grid>
EDIT: Now with screenshot, as requested. It's the right column I'm talking about (So yes, this UserControl is in itself another nested Grid)
EDIT 2: Here's the containing code. My page consist of three classess.
The 1st (ApplicationView.xaml) is a Window. It has the navigation buttons in the left column, a nice line, and one column containing the view of that specific object. It has no rows.
ApplicationView.xaml
<Grid>
<Grid.Resources>
<ResourceDictionary Source="StylesRD.xaml" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="6*" />
</Grid.ColumnDefinitions>
<!-- A DockPanel for the Navigation Buttons-->
<DockPanel Grid.Column="0" Margin="0,20" VerticalAlignment="Top" HorizontalAlignment="Center">
<ItemsControl ItemsSource="{Binding PageViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"
Margin="2,5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
<Line Grid.Column="1" Style="{StaticResource verticalLineStyle}" />
<ContentControl Grid.Column="2" Content="{Binding CurrentPageViewModel}" />
</Grid>
The view (CustomerView.xaml) is the 2nd file. It is a User control and it also has 3 columns, one with the list of Customers in this case, one for the beautiful seperating line (it is beautiful, right? /sarcasm) and the one I'm struggling with right now with the details and the buttons to do stuff.
Here also no rows.
CustomerView.xaml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<!-- Customer list -->
<view:CustomerListView Grid.Column="0" VerticalAlignment="Top"/>
<Line Grid.Column="1" Style="{StaticResource verticalLineStyle}" />
<!-- Details -->
<view:CustomerDetailsView Grid.Column="2" VerticalAlignment="Top"/>
</Grid>
Your inner Grid has two RowDefinitions without a height setting. Therefore the default Height="*" will be used for both rows. Your inner grid doesn't need two RowDefinitions, so removing them should fix your issue. So your inner grid definition should look like this:
<Grid>
<!--
remove these row definitions
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="TBCustomerTitle" Margin="0,0,8,0" FontWeight="Bold"
Visibility="{Binding SetVisibility, UpdateSourceTrigger=PropertyChanged}">Customer:</TextBlock>
<TextBox Name="TBCustomerData" Grid.Column="1"
Visibility="{Binding SetVisibility, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding DisplayedCustomer.Name, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Grid>
Edit:
It works for me as expected. The TextBox and TextBlock get stretched to 2* height, and the two StackPanels have a height of 1* each. Please provide the XAML where you use your user control. Seems like there lies the problem.
Edit 2:
Ah, now I see it. The VerticalAlignment="Top" setting in your CustomerView.xaml pushes your CustomerDetailsView to the top. Either remove this attribute or set the VerticalAlignment to Stretch.
The xaml you provided is working fine, the problem is in the containing xaml. Look at this example xaml.
<StackPanel Orientation="Horizontal">
<Border Background="Yellow">
<local:MyUserControl/>
</Border>
<StackPanel Background="Green">
<local:MyUserControl/>
</StackPanel>
</StackPanel>
And the usercontrol (stripped away bindings and styles)
<UserControl x:Class="WpfApplication3.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication3"
mc:Ignorable="d">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="TBCustomerTitle" Margin="0,0,8,0" FontWeight="Bold" >Customer:</TextBlock>
<TextBox Name="TBCustomerData" Grid.Column="1" Text="{Binding DisplayedCustomer.Name, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Grid>
<Line Grid.Row="1" Height="5"/>
<StackPanel Grid.Row="2" Orientation="Vertical">
<Button Command="{Binding AddCommand}">Add a new customer</Button>
<Button Command="{Binding UpdateCommand}">Update the selected customer</Button>
<Button Command="{Binding DeleteCommand}">Delete the selected customer</Button>
</StackPanel>
<Line Grid.Row="3" Height="5"/>
<StackPanel Grid.Row="4" Orientation="Vertical">
<Button Command="{Binding RefreshCommand}">Refresh the list</Button>
<Button Command="{Binding ClearSelectionCommand}">Clear selection</Button>
</StackPanel>
</Grid>
</UserControl>
As you can see the usercontrol located in the stackpanel is not stretching because stackpanel does not stretch it's contents.
I can't figure out why the contents of my TextBox is affecting my grid column widths. I have setup a grid with 3 columns with widths defined as 50, *, 50, as shown below
Now, when in use, the center column will grow/shrink as the text in the TextBox changes, see the 2 examples below. The actual TextBox is not changing size, so I can't understand why in the world the grid is changing. The Grid is inside of a Border inside a UserControl. The UserControl is used as a DataTemplate in a ListBox.
Edit: I've discovered that this issue is related to the UserControl being in a ListBox, see example image below (UserControl in ListBox (circled in red) vs. UserControl Placed on Form (circed in blue). The grid behaves as expected when the UserControl is placed directly on the form. Code for the form is given below.
UserControl XAML:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Name:" Margin="2" />
<TextBox Grid.Column="1" Margin="2" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Grid.ColumnSpan="2" />
<TextBlock Text="Shift:" Grid.Row="1" Margin="2" />
<TextBox Grid.Column="1" Grid.Row="1" Margin="2" Text="{Binding TimeShift, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, FallbackValue=0}" HorizontalContentAlignment="Right" />
<TextBlock Text="s" Grid.Row="1" Grid.Column="2" Margin="2" />
</Grid>
Window/Form XAML:
<Window x:Class="CrashSimOffice.FileImport"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CrashSimOffice"
Title="File Import" Height="350" Width="450" Background="White" Icon="/CrashSimOffice;component/Images/16/page-white-save.png">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="75"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Content="Add" Margin="2" Command="{Binding AddFileCommand}" />
<Button Content="Remove" Grid.Column="1" Margin="2" Command="{Binding RemoveFileCommand}" />
<ListBox HorizontalContentAlignment="Stretch" Grid.ColumnSpan="4" Margin="2" Grid.Row="1" ItemsSource="{Binding Files}" SelectedItem="{Binding CurrentFile}" ScrollViewer.CanContentScroll="False" Background="WhiteSmoke">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:FileViewModel}">
<local:FileView DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Done" Grid.Column="3" Margin="2" Grid.Row="2" Click="Button_Click" />
<local:FileView Grid.Row="3" Grid.ColumnSpan="4" />
</Grid>
OK, I figured it out, Bruno V you got me thinking it must have something to do with the ListBox. I needed to add this to my ListBox:
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Not sure why that works, but it does.
I have the following XAML source to demonstrate what I am working on.
I want, when resizing the group vertically, is to have the first groupbox expand, up to its max height, then, when that is reached, expand the third groupbox.The third groupbox has a min height property, as well.
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="Screen_1_Name"
x:Class="TestExpansionScreens.Screen_1"
Width="400" Height="400">
<Grid x:Name="LayoutRoot" Background="White" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<GroupBox Header="Thing1" Background="LightGreen" Grid.Row="0" Grid.Column="0" MaxHeight="350">
<Button Content="Stuff1" />
</GroupBox>
<GroupBox Header="Thing2" Background="LightBlue" Grid.Row="1" Grid.Column="0">
<TextBox Text="Stuff2" Height="60" />
</GroupBox>
<GroupBox Header="Thing3" Background="Pink" Grid.Row="2" Grid.Column="0">
<TextBox Text="Stuff3" />
</GroupBox>
</Grid>
</UserControl>
Normally, when I just want a single control expanded to fill the available space, I use a DockPanel. I've built this example with all kinds of assortments of grids and dockpanels, however, I have been unable to resolve how to make it work. Any idea on how to make it happen?
Thanks
You have to set the MaxHeight on your first RowDefinition, not on the GroupBox. The row will grow up to that height and then all excess space will be occupied by the third row. You can also add a MinHeight to the third row.
<Grid x:Name="LayoutRoot" Background="White" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition MaxHeight="350" />
<RowDefinition Height="Auto"/>
<RowDefinition MinHeight="150" />
</Grid.RowDefinitions>
<GroupBox Header="Thing1" Background="LightGreen" Grid.Row="0" Grid.Column="0">
<Button Content="Stuff1" />
</GroupBox>
<GroupBox Header="Thing2" Background="LightBlue" Grid.Row="1" Grid.Column="0">
<TextBox Text="Stuff2" Height="60" />
</GroupBox>
<GroupBox Header="Thing3" Background="Pink" Grid.Row="2" Grid.Column="0">
<TextBox Text="Stuff3" />
</GroupBox>
</Grid>
So I have a following XAML code:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="214" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="42" />
</Grid.RowDefinitions>
<toolkit:BusyIndicator IsBusy="False" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<StackPanel Grid.Column="0" Grid.Row="0">
<!-- ... -->
</StackPanel>
<Canvas Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<!-- ... -->
</Canvas>
</toolkit:BusyIndicator>
<TextBlock Grid.Row="1" Grid.ColumnSpan="2" />
</Grid>
The idea is to have BusyIndicator to cover both cells in the first row and leave second row as is. But XAML editor in Visual Studio underlines <Canvas> and says: "The property 'Content' is set more than once."
How to overcome this?
You're getting the error about 'Content' being set more than once because a BusyIndicator is a ContentControl and can only have at most one child.
What you can do instead is put the BusyIndicator inside the grid as siblings of your StackPanel and Canvas. To ensure that it appears above the other controls in the top row when it is busy, use the property Canvas.ZIndex. This needs to have a higher Z-index than any controls within your stackpanel and canvas. (If you're not using Z-indexes in your stackpanel and canvas, 1 will do, as in the example below.)
<Grid>
<!-- ... -->
<toolkit:BusyIndicator IsBusy="False" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Canvas.ZIndex="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/ >
<StackPanel Grid.Column="0" Grid.Row="0">
<!-- ... -->
</StackPanel>
<Canvas Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<!-- ... -->
</Canvas>
<TextBlock Grid.Row="1" Grid.ColumnSpan="2" />
</Grid>
Im trying to put 4 expander controls inside a Grid with 4 rows, the expander control contains a Grid and a ListBox (Currently holding some sample data).
Ideally when an expander is expanded I want it to fill all the available space without pushing the remaining expanders off the screen or the list box going off the screen. Can anyone think of a way of adapting the XAML below or updating the XAML below to achieve this?
<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource ExpanderData}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.246*"/>
<RowDefinition Height="0.754*"/>
</Grid.RowDefinitions>
<Grid Margin="0" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.275*"/>
<ColumnDefinition Width="0.725*"/>
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<toolkit:Expander x:Name="Expander1" Header="One" IsExpanded="False">
<Grid Background="#FFE5E5E5">
<ListBox Margin="0" ItemTemplate="{StaticResource ItemTemplate}" ItemsSource="{Binding Collection}"/>
</Grid>
</toolkit:Expander>
<toolkit:Expander x:Name="Expander2" Header="Two" IsExpanded="True" VerticalAlignment="Top" Grid.Row="1">
<Grid Background="#FFE5E5E5">
<ListBox Margin="0" ItemTemplate="{StaticResource ItemTemplate1}" ItemsSource="{Binding Collection}"/>
</Grid>
</toolkit:Expander>
<toolkit:Expander x:Name="Expander3" Header="Three" VerticalAlignment="Top" Grid.Row="2" IsExpanded="False">
<Grid Background="#FFE5E5E5">
<ListBox Margin="0" ItemTemplate="{StaticResource ItemTemplate2}" ItemsSource="{Binding Collection}"/>
</Grid>
</toolkit:Expander>
<toolkit:Expander x:Name="Expander4" Header="Four" VerticalAlignment="Top" Grid.Row="3" IsExpanded="False">
<Grid Background="#FFE5E5E5">
<ListBox Margin="0" ItemTemplate="{StaticResource ItemTemplate3}" ItemsSource="{Binding Collection}"/>
</Grid>
</toolkit:Expander>
</Grid>
</Grid>
</Grid>
</Grid>
</UserControl>
I'd probably use a DockPanel instead of a Grid - for Silverlight you'll have to get it from the Silverlight Toolkit (http://silverlight.codeplex.com) - I know you already have it, I'm just referencing it for the archives. Uncheck the "LastChildFill" property and dock all the children to Top.
It's tough to test without adequate data, but what if you just had one Expander open at a time and set the MaxHeight of each Expander to the remaining available space?