Problem with GridSplitter not resizing content - silverlight

First off I'm new to XAML so forgive me if I've done something stupid.
I have stripped down my page to the following example XAML (viewable in XamlPad):
<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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" MinWidth="150" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="3*" />
<!--<RowDefinition Height="Auto" />-->
<RowDefinition MaxHeight="25" Height="25" MinHeight="25" />
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid Grid.RowSpan="4" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
<GridSplitter Grid.Row="0" Grid.RowSpan="4" Width="4" />
<Frame >
</Frame>
<GridSplitter Grid.Row="0" Height="4" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" />
<Grid Grid.Column="2" Grid.Row="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Column="2" Grid.Row="3">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</ScrollViewer>
</Grid>
</Page>
What I want to happen is for the Horizontal Grid Splitter to resize the top panel, moving the bottom Grid (which I want to keep at 25 height) and Scrollviewer controls down.
I've tried putting the Horizontal grid splitter into it's own Row and this moves the content down but it shrinks the content of the top grid which is not what I'm looking for.
Any suggestions as to waht I'm doing wrong? Is it something to do with the proportional height?

Firstly you have defined the splitter as if they apply to multiple rows and columns, but they actually have to have a row or column of their own and they apply to the adjacent rows/columns, so you were on the right track before.
The problem is the proportional (star) rows. For a splitter to work at least one of the adjacent rows/columns has to be fixed (pixel) sized or it does not adjust with the mouse but by some weird proportional movement instead.
I did not understand your "but it shrinks the content of the top grid which is not what I'm looking for" comment, so it might need some more explaining and I have made some guesses, but the XAML file shown below has the splitter behaving themselves:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="191.5" />
<ColumnDefinition Width="8.5"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="194" />
<RowDefinition Height="0.148*"/>
<RowDefinition MaxHeight="25" Height="25" MinHeight="25" />
<RowDefinition Height="0.852*"/>
</Grid.RowDefinitions>
<Grid Grid.RowSpan="4" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.ColumnSpan="2" Margin="0,0,-0.5,0" />
<sdk:GridSplitter Grid.Row="0" Grid.RowSpan="4" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0.5,0,-0.5,0" />
<Frame >
</Frame>
<sdk:GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" Grid.ColumnSpan="3" />
<Grid Grid.Column="2" Grid.Row="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0.5,0,-1,0"/>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Column="2" Grid.Row="3" Margin="0.5,0,-1,0">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</ScrollViewer>
</Grid>

If I understand your problem correctly.
You should be able to take out the VerticalAlignment="Stretch" and HorizontalAlignment="Stretch" from your inner grid and get what you want.
The gridsplitter doesn't like other content in a different row (or col) that has both Allignments set to stretch.

Related

WPF ScrollViewer pushing control out of window

I have a DockPanel, which contains some controls including a ScrollViewer.
What I WANT to happen, is for the ScrollViewer to allow the grid to be scrolled, without pushing other controls off the bottom of the form.
Instead, the ScrollViewer expands to the height of the window, rather than the top of the Button, pushing the Button off for the bottom of the form. Why is this? How do I fix it?
<Window x:Class="Class1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Class1"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="600"
WindowStartupLocation="CenterScreen">
<DockPanel LastChildFill="False">
<Menu DockPanel.Dock="Top">
<MenuItem Header="File">
<MenuItem Name="miQuit" Header="Quit" Click="miQuit_Click" />
</MenuItem>
</Menu>
<ToolBarTray DockPanel.Dock="Top" IsLocked="True">
<ToolBar>
<Button Name="btnQuit" ToolBar.OverflowMode="Never" Click="btnQuit_Click">
Quit
</Button>
</ToolBar>
</ToolBarTray>
<ScrollViewer VerticalScrollBarVisibility="Auto" DockPanel.Dock="Top" VerticalAlignment="Stretch">
<Grid Name="gMainGrid" ScrollViewer.CanContentScroll="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox Grid.Column="0" Grid.Row="0" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="1" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="2" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="3" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="4" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="5" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="6" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="7" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="8" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="9" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="10" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="11" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="12" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="13" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="14" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="15" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="16" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="17" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="18" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="19" Width="100" Margin="10,10,10,10"/>
<TextBox Grid.Column="0" Grid.Row="20" Width="100" Margin="10,10,10,10"/>
</Grid>
</ScrollViewer>
<Button Name="btnButton1" DockPanel.Dock="Bottom" Click="btnButton1_Click" >ButtonText</Button>
</DockPanel>
I want the menu bar at the top of the screen, the button at the bottom of the screen, and the grid with the ScrollViewer in the middle. What am I doing wrong?
The problem is that the ScrollViewer doesn't know how much height it should get. ScrollViewer is a control that tries to get as much size as its children need. DockPanel also gives as much size as the ScrollViewer need and therefore your problem. You can fix height of the ScrollViewer with pixels (i.e. Height=100) To make it a fixed height. I don't know your use case so this might be useful if you are showing an image carousel for example.
In more general layout advice I might say that you'd better use a grid instead of a DockPanel:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<!-- Next one is for middle part of the page -->
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<!-- your controls here -->
</Grid>
I found that I could have a dynamic height with the DockPanel if I stuck the whole thing in a Grid. This appears to work, as I can now have a dynamic height for the ScrollViewer.
<Window x:Class="Class1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Class1"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="600"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DockPanel Grid.Column="0" Grid.Row="0" LastChildFill="False">
Everything is then as normal EXCEPT that I move my button outside of the DockPanel and into the Grid's second row:
</DockPanel>
<Button Grid.Column="0" Grid.Row="1" Name="btnButton1" DockPanel.Dock="Bottom" Click="btnButton1_Click" >ButtonText</Button>
</Grid>
The rows with a Height of "Auto" will size to fit their content. The rows with a Height of asterisk (*) will size to fill the remaining space after the size of the Autos has been calculated. Thus everything sizes up correctly and nicely.
Alternatively, at this point I can do-away with the DockPanel entirely and have the Menu, ToolBarTray, ScrollViewer, and Button in their own separate grid rows, like Emad suggests in their answer (although I'm not sure what the extra row is for in their example).
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
I ultimately decided to go for that approach, so I'll mark it as the answer, but I'm putting this all here for the full explanation, for completeness (in case people do happen to want to keep their DockPanel).

How to have one control expand/fill up to maxheight, then expand/fill another control in WPF?

I have the following XAML source to demonstrate what I am working on.
I want, when resizing the group vertically, is to have the first groupbox expand, up to its max height, then, when that is reached, expand the third groupbox.The third groupbox has a min height property, as well.
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="Screen_1_Name"
x:Class="TestExpansionScreens.Screen_1"
Width="400" Height="400">
<Grid x:Name="LayoutRoot" Background="White" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<GroupBox Header="Thing1" Background="LightGreen" Grid.Row="0" Grid.Column="0" MaxHeight="350">
<Button Content="Stuff1" />
</GroupBox>
<GroupBox Header="Thing2" Background="LightBlue" Grid.Row="1" Grid.Column="0">
<TextBox Text="Stuff2" Height="60" />
</GroupBox>
<GroupBox Header="Thing3" Background="Pink" Grid.Row="2" Grid.Column="0">
<TextBox Text="Stuff3" />
</GroupBox>
</Grid>
</UserControl>
Normally, when I just want a single control expanded to fill the available space, I use a DockPanel. I've built this example with all kinds of assortments of grids and dockpanels, however, I have been unable to resolve how to make it work. Any idea on how to make it happen?
Thanks
You have to set the MaxHeight on your first RowDefinition, not on the GroupBox. The row will grow up to that height and then all excess space will be occupied by the third row. You can also add a MinHeight to the third row.
<Grid x:Name="LayoutRoot" Background="White" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition MaxHeight="350" />
<RowDefinition Height="Auto"/>
<RowDefinition MinHeight="150" />
</Grid.RowDefinitions>
<GroupBox Header="Thing1" Background="LightGreen" Grid.Row="0" Grid.Column="0">
<Button Content="Stuff1" />
</GroupBox>
<GroupBox Header="Thing2" Background="LightBlue" Grid.Row="1" Grid.Column="0">
<TextBox Text="Stuff2" Height="60" />
</GroupBox>
<GroupBox Header="Thing3" Background="Pink" Grid.Row="2" Grid.Column="0">
<TextBox Text="Stuff3" />
</GroupBox>
</Grid>

WPF: Inner content wont scroll

I have a Window with a Grid inside:
<Grid KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="70" />
<RowDefinition Height="*" />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" Content="{Binding ChildViewModel.View}" />
<DockPanel Grid.Row="1" Visibility="{Binding SearchResultViewVisibility}">
<GridSplitter DockPanel.Dock="Top" Background="LightGray" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Top" IsTabStop="False"/>
<Views:SearchResultView DataContext="{Binding SearchResultViewModel}" />
</DockPanel>
<UserControls:GradientBackgroundControl Grid.Row="2" Height="25">
<Validators:FocusSummaryControl x:Name="FocusSummary" ValidateOnlyFocusedElement="False" />
</UserControls:GradientBackgroundControl>
</Grid>
The ContentControl gets a UserControl with this Grid set:
<Grid KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Row="0" Grid.ColumnSpan="4">
<StackPanel>
...
</StackPanel>
</ScrollViewer>
The problem now is, that the ScrollViewer in the UserControl doesn't scroll. The content of the UserControl set to the ContentControl is heigher and the overflow ist just hidden.
If I am not wrong, StackPanel requires a Height to be set for scroll functionality to work because StackPanel, by design, grows in one direction (based on Orientation).
To confirm whether this is the cause of your problem, please test by setting the height of StackPanel to a fixed height. Alternately, you may want to replace the StackPanel with say DockPanel and see the behaviour. Also there is a ScrollViewer.CanContentScroll property that you may want to fiddle with.
Let us know the result of this test.
I think you need to rearrange things a little bit. My suggestions (I'm sure there are infinite variations that would work):
First, add a new row to your grid (Height="Auto") and set the height of your top row (with your ContentControl in it) to "*"
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="70" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
Second, move your GridSplitter out of the DockPanel. Put the splitter in row 1 and the dockpanel in row 2.
<ContentControl Grid.Row="0" Content="{Binding ChildViewModel.View}" />
<GridSplitter Grid.Row="1" Background="LightGray" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Top" IsTabStop="False" ResizeBehavior="PreviousAndNext"/>
<DockPanel Grid.Row="2" Visibility="{Binding SearchResultViewVisibility}">
<Views:SearchResultView DataContext="{Binding SearchResultViewModel}" />
</DockPanel>
Note that you'll probably also have to set the ResizeBehavior for your GridSplitter as shown above. I hope this will get you close to what you want.

Use all browser space in Silverlight application

I am currently writing a Silverlight application that will view documents. The main panel is a WrapPanel with controls on the left and bottom of the page. Currently, the WrapPanel width is getting set to whatever it needs to be able to display all document pages on one line and I would like to change it so that it will fill up the rest of the browser window, with no horizontal scroll bar
Here is my current xaml, where <doc:DocumentViewer x:Name="Viewer".. is the wrap panel in question.
<UserControl x:Class="SilverlightXPSViewer.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:doc="http://schemas.firstfloorsoftware.com/documenttoolkit"
mc:Ignorable="d">
<Grid x:Name="LayoutRoot" Background="White" >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<doc:ThumbnailListBox x:Name="Thumbnails" Grid.Row="0" Grid.Column="0" DocumentDataSource="{Binding ElementName=DataSource}" PageIndex="{Binding PageIndex, Mode=TwoWay, ElementName=PageNavigator}"/>
<doc:DocumentViewer x:Name="Viewer" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="3" DocumentDataSource="{Binding ElementName=DataSource}" Width="{Binding ElementName=MainWidth}"/>
<doc:DocumentDataSource x:Name="DataSource" Grid.Row="0" LoadError="DataSource_LoadError" />
<StackPanel Grid.Column="3" Grid.Row="1" Orientation="Horizontal">
<doc:PageNavigator x:Name="PageNavigator" Margin="0"
PageCount="{Binding PageCount, ElementName=Viewer}"
PageIndex="{Binding PageIndex, ElementName=Viewer, Mode=TwoWay}"/>
<doc:PageNavigator />
</StackPanel>
<doc:ViewModePicker Grid.Row="1" Grid.Column="0" x:Name="Collection"/>
<Button Width="200" Name="btnZoomIn" Grid.Row="1" Grid.Column="1" Cursor="Hand" Click="btnZoomIn_Click">Zoom In</Button>
<Button Width="200" Name="btnZoomOut" Grid.Row="1" Grid.Column="2" Cursor="Hand" Click="btnZoomOut_Click">Zoom Out</Button>
</Grid>
</UserControl>
Use the System.Windows.Browser.HtmlPage object to get the available screen size from the HTML DOM (thus letting the browser to tell you how much space there is) and set the control size from that.
here's an example:
http://www.jeff.wilcox.name/2008/06/browserscreeninformation/

How to organize elements inside a Button

i'm new to wpf .
i got a wpf button ,
in it i need to place 2 elements a textblock and a viewbox encapsulating a canvas
the problem is i can't seem to see the canvas at all , unless i give it static values for its size
<Button Margin="10,30,10,10" Padding="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Me" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></TextBlock>
<Viewbox Margin="0,0,0,5">
<Canvas Background="red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="1" >
<Ellipse HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="Black" StrokeThickness="4" ></Ellipse>
</Canvas>
</Viewbox>
</Grid>
</Button>
iv'e also attempted this using a stack panel with an horizontal orintation
in any case the canvas does not show
any thoughts of what i'm doing wrong ?
thanks.
Attached Grid properties only work when at the Grid-child-level, i.e. the properties set on the canvas do not take effect they should be set on the container, the ViewBox which is a direct child of the Grid.
Viewboxes only work if the content has a concrete size, you probably need neither the ViewBox nor the Canvas. If you want the Ellipse to be a circle set Stretch="Uniform"
The contents of Buttons do not stretch by default you should set HorizontalContentAligment and its vertical counterpart to Stretch.
e.g.
<Button Margin="10,30,10,10" Padding="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Me" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></TextBlock>
<Ellipse Stretch="Uniform" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Stroke="Black" StrokeThickness="4"></Ellipse>
</Grid>
</Button>

Resources