Reputation: 8336
The heights of each DataGrid should depend on:
All Extenders should be always visible.
If e.g. opening only upmost Extender and its DataGrid has 100 rows the Height of the DataGrid should be almost the height of StackPanel but in the bottom the two other Extenders should be visible and upmost DataGrid scrollable.
When opening 2 or 3 Extenders the StackPanel should be "full" if there is enough data in DataGrids.
I tried to bind the height properties (for undermost expander Objec information)
<Expander Header="Object information" IsExpanded="{Binding ObjectInformationExpanded}">
<DataGrid Name="ObjectInformationGrid" CanUserAddRows="False" CanUserResizeColumns="True" CanUserSortColumns="True" IsReadOnly="True"
ItemsSource="{Binding SelectedObjectAttributes}" AutoGenerateColumns="False"
Height="{Binding ObjectInformationHeight, Mode=TwoWay}"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Visible">
<DataGrid.Columns>
<DataGridTextColumn Header="Field" Binding="{Binding Item1}" />
<DataGridTextColumn Header="Value" Binding="{Binding Item2}" />
</DataGrid.Columns>
</DataGrid>
</Expander>
But now my ViewModel has lots of code that is related to presentation (View) and still didn't take the StackPanel's height into the calculation. Instead I set the hardcoded double values which can't be good solution.
Here is bit of simple code that updates the bound height Properties (here for upmost DataGrid only) when extenders are opened/closed and DataGrid bound collections are changed:
private void UpdateHeights()
{
if (SelectedObjectsExpanded == true)
{
if (_selectedObjects.Count == 0)
{
SelectedObjectsHeight = double.NaN;
}
else if (_selectedObjects.Count < 8)
{
SelectedObjectsHeight = 100;
}
else
{
if (ObjectInformationExpanded && SelectedSwitchesExpanded)
SelectedObjectsHeight = 100;
else
SelectedObjectsHeight = 200;
}
}
//...
Thanks!
Upvotes: 3
Views: 275
Reputation: 132548
Would something like this work?
The basic idea is put all 3 Expanders
in a Grid containing 3 rows, and bind the RowDefinition.Height
of each row to the Expander.IsExpanded
. A Converter is used to set the value to Auto
if the expander is collapsed (only take up the space needed), or *
if it's expanded (take up all remaining space. If multiple rows are set to *
height, share space evenly between them).
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="{Binding IsExpanded, ElementName=Expander1, Converter={x:Static MyBoolToGridSizeConverter}}" />
<RowDefinition Height="{Binding IsExpanded, ElementName=Expander2, Converter={x:Static MyBoolToGridSizeConverter}}" />
<RowDefinition Height="{Binding IsExpanded, ElementName=Expander3, Converter={x:Static MyBoolToGridSizeConverter}}" />
</Grid.RowDefinitions>
<Expander Grid.Row="0" x:Name="Expander1">
<DataGrid />
</Expander>
<Expander Grid.Row="1" x:Name="Expander2">
<DataGrid />
</Expander>
<Expander Grid.Row="2" x:Name="Expander3">
<DataGrid />
</Expander>
</Grid>
public class BoolToGridSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (value is bool && (bool)value)
return new GridLength(1, GridUnitType.Star);
return GridLength.Auto;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// this is not needed
}
}
Upvotes: 2