Simple grid layout question - wpf

I can't believe I'm back to this after working with WPF for 3 months :)
Consider very common setup:
How do I configure the rowheights so that the top and bottom rows (menu bar and status bar) size to fit the height of their content, and the middle row (main content), fills the remaining available space in the program?
I can't fix the height of the top/bottom rows because the height of their content can vary.
<Window>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Menu Grid.Row=0>
...menuitems
</Menu>
<Grid Grid.Row=1>
...main application content here (like most programs)
</Grid>
<StatusBar>
...statusbaritems
</StatusBar>
</Grid>
</Window>

<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
From GridUnitType Enumeration:
Auto: The size is determined by the size properties of the content object.
Star: The value is expressed as a weighted proportion of available space.

You use:
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
Auto will size to content, and * will fill space. If you had multiple "content" areas in between, you can use multiples, too:
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2*" /> <!-- Will be 2/3rd of main space -->
<RowDefinition Height="1*" /> <!-- Will be 1/3rd of main space -->
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

Related

WPF datagrid height is infinite

I have two datagrids (data grid 1 and 2) which are being bound from a separate User Control:
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0" >
<local:DATAGRID1 x:Name="DATAGRID1" /></Grid>
<Grid Grid.Row="1" Grid.Column="0">
<local:DATAGRID2 x:Name="DATAGRID2" /> </Grid>
<Grid Grid.Row="0" x:Name="AddURLContainer" Grid.Column="1" >
<StackPanel>
<local:test1 x:Name="NewQueryControl"/>
<local:test2 x:Name="AddURLControl" />
</StackPanel>
</Grid>
</Grid>
But for some reason the data grids stretch longer than the window and don't constrain within the windows height. I've attempted to put the Datagrids in a scroll viewer but the scroll bar also goes out of the window and doesn't constrain. I can't figure out why its doing this.
The opening tags of the actual data grids are (and they are wrapped in a User control not a Stackpannel):
<DataGrid AutoGenerateColumns="False"
IsReadOnly="True"
SelectionMode="Single"
>
Seemed to be fixed if I change the above main grids row properties from:
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
To:
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
Strange fix but it works.
Why are using * width and heigt?
Use Auto:
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
Auto set the size to it's allocated content.

Grid in a Grid with RowDefinition Height="auto" suppresses Height="*" of child Grid's RowDefinitions

I have the following code:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" TextBlock.Foreground="Blue" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="test" Grid.Row="0" />
<TextBlock Text="test" Grid.Row="2" />
</Grid>
<Grid Grid.Row="1" TextBlock.Foreground="Red" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="test" Grid.Row="0"/>
<TextBlock Text="test" Grid.Row="2"/>
</Grid>
</Grid>
It's simply two equal grids with three rows, all three which should be of equal size (each in its own grid, that is).
The bottom grid, contained in the parent row with a height of "*" behaves as expected. Each row is of equal size, regardless of what is put into it.
But the top grid, contained in a row with height Auto, seems to discard the Height="*", and behave as if they had Height="Auto". The first and third row gets exactly the height they ask for, and the second, the empty row, is just given a height of 0. Is this normal behaviour? And if so, why is it the way it is?
This is how it appears:
And this is how I would expect it to work:
This behaviour is expected. Height="*" means that all rows will share evenly available space
The value is expressed as a weighted proportion of available space
When you set parent row height to auto it means that child Grid is not stretched vertically any more so there is no free space to share so rows will take only as much space as they need to. It's like you would set VerticalAlignment="Top" for example.
You can achieve what you want by using SharedSizeGroup on the top Grid. In this scenario all rows belong to the same group and all will share same height
<Grid Grid.Row="0" IsSharedSizeScope="True" TextBlock.Foreground="Blue" ShowGridLines="True" >
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="CommonRow"/>
<RowDefinition SharedSizeGroup="CommonRow"/>
<RowDefinition SharedSizeGroup="CommonRow"/>
</Grid.RowDefinitions>
<TextBlock Text="test" Grid.Row="0" />
<TextBlock Text="test" Grid.Row="2" />
</Grid>
it behaves is normally.
when you set Height="*" that means fill the rest of space, while Height="Auto" means fit to all inner controls. so the first row is fitting all the controls that you have which they are only two, and because there is no Height property set to first inner grid or TextBlocks it takes only the height that equal yourFirstTextBlock.Height + yourSecondTextBlock.Height.

Row height of grid based on the contents and other row visibility

I have a grid the row definitions are as following
<Grid.RowDefinitions>
<RowDefinition Height="5*" />
<RowDefinition Height="5*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
Now all the first three rows would be always visible but out of 4th and 5th row only one would be visible. How can I assign the row height property equally among all the four visible rows
You can share the available Height equally between the top four rows like this:
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
However, if the last row is not visible, that sounds to me like the parent of the Grid is not set up correctly... you should always see all of the rows unless you have a problem. Is the Grid inside a StackPanel or Canvas? I ask that because these containers do not adjust the size of their children like aGrid` does and should only be used in certain situations.

How can I get the actual grid row height of a grid with RowDefinition Height *

<Grid x:Name="SidebarGrid" LayoutUpdated="gridlayoutupdated">
<Grid.RowDefinitions>
<RowDefinition Height="250" />
<RowDefinition Height="*"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
The Row sizes to content, but after the content is set, I would like to get the height.
You can use RowDefinition.ActualHeight (but note that it is not data-bindable).

Resizing another grid row size in WPF

I am wondering is there any way to solve this by changing XAML code?
Please look at this sample picture:
What I wants to do is when user dragging GridSeparater No.1, I want to resize thr 3rd row of grid.
This is because in this application, the first and third rows are variable size, but second one is fixed size.
Is that possible?
This is possible with ResizeBehaviour="PreviousAndNext" (Link to MSDN). This enables you to specify which rows should be affected relative to the GridSplitter.
<Grid Width="300" Height="200" Background="Yellow" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<GridSplitter Grid.Row="1"
ResizeDirection="Rows"
ResizeBehavior="PreviousAndNext"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Background="Black"
ShowsPreview="True"
Height="5"
/>
</Grid>
You could try setting both MinHeight and MaxHeight to the same value on the center row which would force recalculation of the bottom section when resizing the top. Something like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="50" MaxHeight="50" MinHeight="50"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
... other content
<GridSplitter Height="3" Grid.Row="1" HorizontalAlignment="Stretch"/>
<GridSplitter Height="3" Grid.Row="3" HorizontalAlignment="Stretch"/>
</Grid>

Resources