WPF Window formatting not working as expected - wpf

I have a WPF windows where I want a section of at the top of the Window to be just the height of all the elements contained in it. The bottom section of the window should be be the adjustable height area. If the window made taller, then the bottom section should be the section that grows and not the top section.
Inside the bottom section of the window, I want two sections contained in it. The top section should be the adjustable height section and the bottom section should be just the height needed to display all the elements contained in it.
If you look at the xaml code below, you will see I have a total of three grids defined. The outer grid has two row definitions where the top row is set to Auto so that the height is just enough to contain all the elements contained in it. The second row should be adjustable to allow it to fill the rest of the size of the window.
Inside the second row of the outer grid is another grid that should allow for the first row to be flexible for height and the second row to be just tall enough for all the elements contained in it.
The problem I am having is that the entire window is not filled. The bottom grid is only part way down on the outer window. Why isn't the entire window filled by the bottom grid? How can I change the definition to allow for this?
<Window x:Class="WPFSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="*" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid x:Name="TopGrid" VerticalAlignment="Top" Width="Auto" Height="Auto" Grid.Row="0">
<Button Height="23" HorizontalAlignment="Left" Margin="60,0,0,4" Name="button1" VerticalAlignment="Bottom" Width="75">Button</Button>
</Grid>
<Grid x:Name="BottomGrid" Width="Auto" Height="Auto" VerticalAlignment="Bottom" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Button Grid.Row="0" Height="23" Margin="60,0,61,4" Name="button2" VerticalAlignment="Bottom">Button</Button>
<Button Grid.Row="1" Height="23" Margin="60,0,61,4" Name="button3" VerticalAlignment="Bottom">Button</Button>
</Grid>
</Grid>

I figured this one out. I had multiple row definitions defined besides just the two I thought I had. Once I removed the extra ones, the formatting worked as expected.

Related

How do I make a WPF layout Grid fill all available vertical space?

I have a form with two Grid elements in a vertical StackPanel. I would have imagined the bottom Grid would automatically fill all available space, as I wish it to, but I have set heights on the Grid rows:
<RowDefinition Height="20" />
<RowDefinition Height="*" />
<RowDefinition Height="25" />
The short rows at the top and bottom are for labels and buttons, respectively. I have tried setting the grid's VerticallAllignment to Stretch, to no avail.
How do I anchor the bottom of the bottom grid to the bottom of the form, regardless of the form's height?
Essentially you can't use StackPanel to fill all available vertical space.
But you may use a DockPanel:
<DockPanel LastChildFill="True">
<Grid DockPanel.Dock="Top"/>
<Grid />
</DockPanel>
You may also use a Grid:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0"/>
<Grid Grid.Row="1"/>
</Grid>

Displaying and resizing a GridRow when a certain height of child control is reached

I cannot seem to get my Grid right. I need a layout with two rows, the first row has a dynamic height based on a child grid's height. The second row contains a couple of Buttons, this row has a constant height of 30 pixels. When the content of the child grid has not yet reached a height of 842 pixels, the window should compress to fit the content. Otherwise, it expands based on the child Grid's height.
If the content of the child grid reaches 842 pixels, I wanted to display a scroll bar only for the first Grid row.
I have played around with MinHeight and MaxHeight but nothing has worked so far. Right now, the scroll bar appears far too late and the window doesn't compress when there is no content in the child grid.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition MaxHeight="35px" Height="35*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Row="0" Grid.Column="0" VerticalScrollBarVisibility="Auto" MinHeight="842px" Margin="0,0,0,13" Grid.RowSpan="2">
<Grid>
<Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
</Grid.RowDefinitions>
//Many controls here...
</Grid>
</ScrollViewer>
<Button Grid.Column="0" Grid.Row="1"></Button>
<Button Grid.Column="0" Grid.Row="1"></Button>
</Grid>
EDIT: Added a picture for clarification.
Like this?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" SizeToContent="WidthAndHeight">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<ScrollViewer Background="Yellow" Grid.Row="0" VerticalScrollBarVisibility="Auto" MaxHeight="842" Margin="0,0,0,13">
<Grid>
<Rectangle Fill="Red" Width="100" Height="300" HorizontalAlignment="Center" VerticalAlignment="Center"></Rectangle>
</Grid>
</ScrollViewer>
<Button Grid.Row="1">But</Button>
</Grid>
</Window>

Preserving minimum sizes with multiple WPF grids and splitters

I have a problem getting an arrangement of grids, splitters and an expander to work correctly, especially regarding setting min heights. I’ve followed a number of suggestions posted here (especially regarding how to combine a splitter and an expander), and have got the basic architecture working, but I can’t get the final details to work right. I’m sure that I could get something working by trial-and-error, especially if I do some brute force work in the code-behind, but I’m guessing there are some fundamental principles of how WPF resizing works that I’m missing here.
The following xaml is a simplified version of the actual structure, with colors and borders added for clarity. I’ve removed my attempts at setting MinHeights. (There is currently no code-behind.)
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="450"
Height="600">
<Grid Background="Yellow">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox x:Name="Tree" Grid.Row="0" Text="Tree" BorderThickness="2" BorderBrush="Red" />
<Expander IsExpanded="True" Grid.Row="1" Header="Expand/Collapse Details" ExpandDirection="Down"
BorderThickness="2" BorderBrush="Black" VerticalAlignment="Bottom">
<Expander.Content>
<Grid x:Name="LowerAreaGrid" Margin="4">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<GridSplitter HorizontalAlignment="Stretch" Grid.Row="0" Height="8" Background="DarkGray"
ResizeDirection="Rows" ResizeBehavior="CurrentAndNext" />
<Grid x:Name="DetailsPaneAndSubpane" Margin="4" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" MaxHeight="{Binding ActualHeight, ElementName=DetailsPane}"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Row="0">
<TextBox x:Name="DetailsPane" Text="This is the Details Pane. It is 150 pixels high. If the available space is too small, it will grow a scrollbar to see all the content."
TextWrapping="Wrap" BorderThickness="4" BorderBrush="Green" Height="150"/>
</ScrollViewer>
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" Height="8" Background="Brown"
ResizeDirection="Rows" ResizeBehavior="PreviousAndNext" />
<Border BorderThickness="4" Grid.Row="2" BorderBrush="Blue">
<Grid x:Name="SubpaneAndButtons" Margin="4" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="This is the Details Subpane. It can grow and shrink."
BorderThickness="2" BorderBrush="Blue"/>
<Grid x:Name="SubpaneButtons" Grid.Row="1" Background="Blue" Margin="4">
<Button Width="200">Do something with subpane</Button>
</Grid>
</Grid>
</Border>
</Grid>
</Grid>
</Expander.Content>
</Expander>
<Grid x:Name="CommandButtons" Grid.Row="2" Background="Pink" Margin="4">
<Button Width="200">Do something with whole window</Button>
</Grid>
</Grid>
</Page>
As you can see, the window has two main areas. There is a tree in the top pane, and when an item in the tree is selected, the bottom area (which is contained in an expander) shows details about the item. There is a splitter that can change the relative sizes of the top and bottom areas. The details area is further divided into two parts: a Details Pane which has a fixed maximum size, and a bottom Details Subpane which can grow and shrink. A second splitter controls the relative sizes of the Details Pane and Details Subpane.
There’s also a button at the bottom of the window that represents a set of buttons that are commands that apply to the whole window. There’s a button at the bottom of the Details Subpane that represents a set of buttons that are commands that apply only to the Details Subpane.
Here’s what doesn’t work:
Problem: the second (brown) splitter can’t be moved up initially. (It’s not expected to be able to move down, since the Details Pane is at its maximum size.) You have to move the gray splitter a little bit, then the brown splitter works fine even if you move the gray splitter back to where it was.
The Tree should have a MinHeight of 75. Problem: putting this in the tree’s RowDefinition causes the rest of the content to slide off the end of the window when you drag the slider up past the 75 pixel mark. (If you don’t have a MinHeight, this sliding occurs when the splitter is dragged up past the top of the window.)
The Details Pane and the Details Subpane should have a MinHeight of 50. Problem: moving either of the splitters down can squish these areas down to nothing.
Neither splitter should affect the “Do something with subpane” button row. It should always be fully visible, unless the expander is collapsed. Problem: again, moving either of the splitters down can squish this area down to nothing.
Here’s what works, and should keep working after all changes are made:
When the “Expand/Collapse Details” expander is collapsed, it collapses everything but the “Do something with whole window” button row. The Tree takes all the remaining space.
The Details Pane is a fixed size (150 pixels). It can’t grow larger than that, and if it is given less space than that, it will grow a scrollbar to allow the entire 150 pixels to be seen still.
What changes need to be made (either in xaml or code-behind) to get this to work?

Silverlight: How can I make this control take up all available space?

I'm building an SL 4 app. The UI consists of three main parts: a top search bar, a bottom favorite bar, and the page content between the two. I would like the page content to take up all available space. Right now, it expands horizontally but not vertically. I'm not sure what I'm doing wrong. Here is the XAML:
<Grid x:Name="LayoutRoot" Background="BurlyWood">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<my:TopSearchBar x:Name="topSearchBar" Grid.Row="0" Navigator="{Binding ElementName=navigationFrame}" HorizontalAlignment="Stretch" VerticalAlignment="Top" />
<!-- I want this to take up all available space between the bottom and top elements -->
<navigation:Frame x:Name="navigationFrame" Source="/HomePage.xaml" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="BlueViolet" />
<my:BottomFavoritesBar x:Name="bottomFavoritesBar" Grid.Row="2" Navigator="{Binding ElementName=navigationFrame}" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" />
</Grid>
What could I be doing wrong?
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
I can't reproduce your problem. For me, the grid does expand vertically to fill its space, and each of its child controls takes a third of the height.
Do you have this Grid inside something else, like a StackPanel, that would prevent it from filling all the vertical space?

Dragging GridSplitter causes cell to grow when using Auto height/width

I am using a GridSplitter to resize a cell in a grid however its behaviour is not what I am expecting and I cannot find a solution. It is a grid of three rows, the first has a row definition set to Auto and contains some elements. The second row has some data in it and has a row definition of * to fill the remaining space. The last row is a status bar that needs to be resizable, and so has a grid splitter in it and a row definition height of Auto and MinHeight of 30.
The problem is when you drag the GridSplitter all the way to the top, it will make the cell overflow. I wish for it to STOP once it gets to the top. The desired behaviour can be achieved by removing the Height=Auto from the last row, but that makes the bottom cell expand to equal height with the middle row.
Here is a XAML Pad example.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" MinHeight="20" />
<RowDefinition Height="Auto" MinHeight="30" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Foo" />
<TextBlock Grid.Row="1" Text="Bar" />
<GridSplitter Canvas.ZIndex="1" VerticalAlignment="Top" Grid.Row="2" Background="Cyan" Height="5" HorizontalAlignment="Stretch" />
<TextBlock VerticalAlignment="Bottom" Grid.Row="2" TextWrapping="Wrap">LOL<LineBreak/>LOL<LineBreak/>LOL</TextBlock>
</Grid>
</Page>
When you drag to the top, you will notice the bottom text disappears.
I have tried various things, such as putting the grid splitter in its own cell, and Binding Height to another objects ActualHeight etc but none really work that well.
I know it isn't the most well explained question, but any ideas would be greatly appreciated.
Edit:
I have made the GridSplitter with its own row as posted below, but as I mentioned earlier the problem still remains. I have the ResizeBehavior and ResizeDirection also set here.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" MinHeight="20" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="30" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Foo" />
<TextBlock Grid.Row="1" Text="Bar" />
<GridSplitter ResizeDirection="Rows" ResizeBehavior="PreviousAndNext" Grid.Row="2" Background="Cyan" Height="5" HorizontalAlignment="Stretch" />
<TextBlock VerticalAlignment="Bottom" Grid.Row="3" TextWrapping="Wrap">LOL<LineBreak/>LOL<LineBreak/>LOL</TextBlock>
</Grid>
</Page>
An example of what does work is removing the last rows Height="Auto" and changing it to * like so
This however makes the last row equal in size to the row before it and not to the requested size of the cell.
GridSplitter should lie at its own row or column. Experiment with GridSplitter.ResizeDirection and GridSplitter.ResizeBehavior properties.
Take a look at the following articles:
How to: Resize Rows with a GridSplitter
How to: Resize Columns with a GridSplitter
UPDATE
You may provide "star coefficients" to GridLength object. For example:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="95*" MinHeight="20" /> <!--here we are using 95*-->
<RowDefinition Height="Auto" />
<RowDefinition Height="5*" MinHeight="30"/> <!--and here we are using 5*-->
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Foo" />
<TextBlock Grid.Row="1" Text="Bar" />
<GridSplitter ResizeDirection="Rows" Grid.Row="2" Background="Cyan" Height="5" HorizontalAlignment="Stretch" />
<TextBlock VerticalAlignment="Bottom" Grid.Row="3" TextWrapping="Wrap">LOL<LineBreak/>LOL<LineBreak/>LOL</TextBlock>
</Grid>
</Page>
So we have the layout as you need without GridSplitter unclear behaviour.
Drat, beat me to it. I might as well post what I have. Your issue is with the third row definition. When you start scrolling up and the text disappears, the row's height keeps increasing. You could try setting the max height to some restriction, if Eugene's solution doesn't work.

Resources