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?
Related
In my application I need to have a listbox to display at the bottom of the screen. The listbox can be displayed of not (via a menu entry), and must be resizable in height. I placed it in a grid and used a gridsplitter to do the resize part, which works as intended.
My problem is, if no manual resize before, once log begins to appear in the listbox, this listbox does not show a scrollbar but instead in begins growing and takes more space. Once I trigger a resize using the gridsplitter, everything works as intended. What can I do to stop this ?
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0"
Grid.Column="1" />
<GridSplitter Grid.Row="1"
Height="5"
HorizontalAlignment="Stretch"
Visibility="{Binding ShowLogWindow,
Converter={StaticResource Bool2Vis}}" />
<ListBox Grid.Row="2"
VerticalAlignment="Stretch"
ItemsSource="{Binding Toolbox.LogEntries}"
MinHeight="50"
Visibility="{Binding ShowLogWindow,
Converter={StaticResource Bool2Vis}}" />
</Grid>
Set the Height of the third RowDefinition (or the ListBox itself) to 50 or whatever fixed height you want it to have.
Auto means size to content, which means that the height of the last row will grow as the ListBox grows. This is not what you want apparently.
I have a grid with 3 rows. Row #2 is tallest and it hosts WebBrowser control. I want to cover webbrowser with a Border at certain times.
What is WPF way to do that?
What I have below is my starter xaml. I use Visibility to collapse my border to show WebBrowser or set my Border to Visible to cover WebBrowser.
However, after doing so I end up having half of 2nd row covered with browser and other half with nothing.
Basically, I want to simulate a toast message that shows and covers entire area of WebBrowser control in GridRow 2.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Grid.Row="2">
<WebBrowser x:Name="wb"
Loaded="wb_Loaded"/>
</ScrollViewer>
<Border x:Name="myBorder" Background="White"
Visibility="Collapsed"
Grid.Row="2" RowSpan="2">
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center">
//some text here
</StackPanel>
</Border>
<DockPanel HorizontalAlignment="Stretch" Grid.Row="3">
...
</DockPanel>
</Grid>
Use a Grid in Row:2 and show/hide Border/BrowserControl, as Grid allows you to stack things on top of each other.
My question is similar to:
Prevent WPF control from expanding beyond viewable area
with the difference that the accepted solution (specific to the issue with StackPanel) does not really help me much.
I have a Window that currently only contains the following Grid:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="265"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="147*"/>
<RowDefinition Height="173*"/>
</Grid.RowDefinitions>
<Button Content="Button" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="75" Click="Button_Click" Grid.Row="1" Grid.Column="1"/>
<local:BatteryGraphicsView x:Name="batView" HorizontalAlignment="Stretch" ClipToBounds="True" Width="265"/>
</Grid>
I want now that if my GraphicsView extends over the width of its column, that the scrollbars are displayed and the control does not paint it self beyond the bounds of the column.
This happens as soon as I press the button.
The user control basically is a grid that contains WinFormsHosts, when pressing the button there are more columns created for the grid and so the grid grows
(Usercontrol grid xaml)
<ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Auto" ClipToBounds="True">
<Grid x:Name="Maingrid" ClipToBounds="True">
<Grid.RowDefinitions>
<RowDefinition Height="40*"/>
<RowDefinition Height="20*"/>
<RowDefinition Height="40*"/>
</Grid.RowDefinitions>
<WindowsFormsHost x:Name="host1" />
<WindowsFormsHost x:Name="host2" Grid.Row="2"/>
</Grid>
</ScrollViewer>
While the Scollviewer realises that it needs to display it self, the mainGrid anyway is displayed beyond the bounds of the column.
In multiple related posts I saw that you need to set the "ClipToBounds" property to true, but I set the property for every control and there is still no reaction.
The problem is that your ScrollViewer inside your UserControl doesn't know what the GridColumn & and GridRow sizes are.
There are two things you can do.
1: Specify a MAX Width for your Column & Max Height for you Row
2: Instead of adding your scrollViewer in the UserControl, add it in your grid and give it a height and width.
I`m trying to fill whole content of Layout with TreeView control. But I cant get height property to stretch. Here is part of the code:
<Grid Grid.Column="0" Margin="2,2,2,0" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<dataInput:Label Content="{Binding ConverterParameter=TXT_ORG_JEDINICE, Converter={StaticResource Localization}, Source={StaticResource Localization}}" Style="{StaticResource PerspektivaHeader}"/>
<basics:TreeView Grid.Row="1" Height="Auto"/>
</Grid>
Height="Auto" is the default, so it shouldn't be necessary to specify that. To make a control stretch vertically you would usually use VerticalAlignment="Stretch" but again, that is the default, so you don't need to write that explicitly.
How are you making sure that the TreeView is not filling the space as you expect? For example, if you set <TreeView Background="Blue"/> what do you see?
Another question: is this the built in Silverlight tree view, or one from a third party?
Finally, could you show us the XAML surrounding the Grid, as it's possible the problem lies there.
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.