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

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.

Related

Advantage of specifying weighted value for single GridUnitType.Star column / row?

I've seen the following on StackOverflow, and didn't think much of it. But I've then seen it in the documentation from Microsoft when looking at the ScrollBar.ControlTemplate, and thought I must be missing something.
What's the benefit of specifying a weighted value for a RowDefinition or ColumnDefinition when no other definitions make use of GridUnitType.Star?
For example, both those links contain something like:
<Grid.RowDefinitions>
<RowDefinition MaxHeight="18"/>
<RowDefinition Height="0.00001*"/>
<RowDefinition MaxHeight="18"/>
</Grid.RowDefinitions>
My understanding is that this is the same:
<Grid.RowDefinitions>
<RowDefinition MaxHeight="18"/>
<RowDefinition Height="*"/>
<RowDefinition MaxHeight="18"/>
</Grid.RowDefinitions>
So what's the point? Convention, performance, historical? I couldn't see anything in the documentation. What am I missing?
In your example, no other RowDefinition is specifying a height, so by default, all RowDefinition.Heights are set to *-sized. So in your first example, this would be equivalent:
<Grid.RowDefinitions>
<RowDefinition Height="*" MaxHeight="18"/>
<RowDefinition Height="0.00001*"/>
<RowDefinition Height="*"MaxHeight="18"/>
</Grid.RowDefinitions>
Meaning, if Height is < 18 for those two columns, then the second RowDefinition will own 0.00001/2.00001 of the available space in the grid.

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.

WPF Grid layout

Is it possible to design something like this using Grid in WPF? Design columns is easy, but what about rows? Or is there any better solution, like another container? Imagine each rectangle as module (GroupBox).
Make an outer Grid with two columns. Within this grid, place two other grids, one per column. This will lead to the desired layout.
Here an example of how to do. Please note that I have placed some stars for the heights. Change them accordingly to your needs.
<Grid>
<Grid.ColumnDefinitions>
<Grid.ColumnDefinition Width="*" />
<Grid.ColumnDefinition Width="*" />
<Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Here content elements of the first column -->
</Grid>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Here content elements of the second column -->
</Grid>
</Grid>
Define your columns and rows.
Put each Groupbox on the desired row and column, and set its rowspan in order to define on how many rows it stretches.

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).

Simple grid layout question

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>

Resources