Automatic resizing of user controls when parent window is resized - c#

I am working on a C# WPF project and I am making use of user controls but I am having a problem with getting the resize to work when the parent window is resized.
I have a Window called MainWindow which houses a canvas which will host the user controls. When Main Window is resized the user controls should also resize. This is more a less working except it doesn't seem to fill up the who screen. Below is the code and screenshots to explain what I mean.
Main Window
Below is the code for the Main Window, this window will host the user controls
<Window x:Class="ReportReader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="513" Width="925" WindowStartupLocation="CenterScreen">
<Grid>
<Menu Height="23" Name="menu1" VerticalAlignment="Top">
<MenuItem Name="mnuFile" Header="File">
<MenuItem Name="mnuOpen" Click="mnuOpen_Click" Header="Open" />
<MenuItem Name="mnuClose" Click="mnuClose_Click" Header="Close Report" />
<MenuItem Name="mnuRecentFile" Header="Recent Files" />
<Separator />
<MenuItem Name="mnuExit" Click="mnuExit_Click" Header="Exit" InputGestureText="Alt+F4" />
</MenuItem>
</Menu>
<StatusBar Name="statusBar1" Height="28" VerticalAlignment="Bottom" />
<Label Content="No Report Loaded" Name="lblStatus" Height="28" VerticalAlignment="Bottom" Margin="0,0,39,0" />
<Grid Margin="12,29,12,34" Name="MainWindowHostCanvas" Background="Blue" />
</Grid>
</Window>
The canvas is coloured blue so it shows my problem in the screenshots.
Below is the code for one of the user controls
<UserControl x:Class="ReportReader.UserControls.ReportViewer"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignWidth="879">
<Grid Height="415">
<Label Content="Report for..." Margin="12,12,12,0" Name="lblReportDateTitle" FontSize="26" FontWeight="Bold" HorizontalContentAlignment="Center" Height="44" VerticalAlignment="Top" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="12,62,0,0" Name="cboRegisteredApps" VerticalAlignment="Top" Width="202" SelectionChanged="cboRegisteredApps_SelectionChanged">
<ComboBoxItem Content="Select App" IsSelected="True" />
</ComboBox>
<DataGrid AutoGenerateColumns="False" Margin="14,203,12,12" Name="dataExceptionGroups" />
</Grid>
</UserControl>
Below is a screenshot of the User Control hosted by the Main Window from when the program first loaded up.
As you can see the blue canvas fills the whole window up to the status bar, the data grid, is at the bottom of the window, just above the status bar, and the report title is at the top of the window just above the menu bar.
Below is the screen shot now that the window has been resized
As you can see from this screenshot, the window has been resized and the blue canvas has resized to fill up the extra space, however, the datagrid is no longer at the bottom of the window, just above the status bar and instead floating around the middle. Also the title at the top is no longer just under the menu bar, and is also in the middle.
I'm not sure what I can do to resolve this.
Thanks for any help you can provide.

Your Grid within UserControl has fixed Height set to 415 which is why it does not stretch:
<UserControl>
<Grid Height="415">
If you're using designer to create your interface then it has tendency to set these properties to fixed values.

If Height="*" is set then all the rows would share the available space equally. If you want to set in % then you can set some thing like this
<Grid.RowDefenitions>
<RowDefenition Height="10*"/>
<RowDefenition Height="20*"/>
<RowDefenition Height="60*"/>
<RowDefenition Height="10*"/>
</Grid.RowDefenitions>
now when ever the window is re-sized always same percentage will be shared for all the rows
It is not necessary the height value in all the rows should sum up to 100. For example if you have three rows then you can set as below as well
<Grid.RowDefenitions>
<RowDefenition Height="20*"/>
<RowDefenition Height="30*"/>
<RowDefenition Height="10*"/>
</Grid.RowDefenitions>
then the total window size will be divided among the all the three rows as follows
for 1st row height will be WindowSize*20/(20+30+10)
for 2nd row height will be WindowSize*30/(20+30+10)
for 3rd row height will be WindowSize*10/(20+30+10)
All the Row sizes will re-size accordingly when ever window size is re-sized

You are using Static Sizing with margin's and height's with hard coded values.
1) Remove all the hard coded values for margin's height and width.
2) Split your grid using Row/Column Definitions with relative height using * , FYI you can set MinHeight
on RowDefenition .
<Grid>
<Grid.RowDefenitions>
<RowDefenition Height="*"/>
<RowDefenition Height="*"/>
<RowDefenition Height="*"/>
<RowDefenition Height="*"/>
</Grid.RowDefenitions>
<Menu>
.....
</Menu>
<StatusBar Grid.Row="1"/>
<Label Content="No Report Loaded" Grid.Row="2" />
<Grid Grid.Row="3" />
</Grid>
Do the same for the UserControl.

Related

Changing size of User Control

I'm having a problem with determining which element is responsible for a size misalignment. Here is a picture to illustrate it: click here to see it
The light grey area is the element size which I am trying to change, but cannot. The overall area is a User Control, the area inside the Tab is a WPF (as an element Host). I've tried changing both, but with no effect on the grey area (the other tabs are also affected by this). Here is the code for the hosted element (WPF):
<UserControl x:Class="SlideAnalyzer.DisplayAnalysis"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SlideAnalyzer"
mc:Ignorable="d"
d:DesignHeight="150.8" d:DesignWidth="201.2">
<Grid Name="displayGrid" Height="64" VerticalAlignment="Bottom" HorizontalAlignment="Center" Width="160" Margin="10,0,31.6,9.4" RenderTransformOrigin="0.496,0.94">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Expander x:Name="expander" Grid.Row="0" Header="Titel zu lang" HorizontalAlignment="Left" VerticalAlignment="Top" Width="180" Background="Red" Margin="-10,-56,0,0">
<Grid Background="AliceBlue">
<TextBlock TextWrapping="Wrap"
Margin="5"><Run Text="This is some text content."/></TextBlock>
</Grid>
</Expander>
</Grid>
The host itself is a normal User Control. I cannot seem to get the right size of the hosted element so that the preview really reflects reality (because when I run the Add-In, the size of the WPF differs)
I tried changing the Properties of the UserControl and I found that AutoSize has a big impact when True (by default False)
Thanks!

WPF controls do not align

NOTE: This is one of the first time I'm using WPF.
I am trying to align a certain control, let's say a button for now, in the bottom right corner. But when I debug my application, it misses 8 pixels to the bottom and right. I will attach 2 pictures to show you what happens.
How do I keep the button in place?
My XAML code:
<Window x:Class="Plugin_Manager.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Plugin Manager" Height="350" Width="525" Loaded="Window_Loaded_1">
<Grid x:Name="GridMain">
<Button Content="Refresh" Margin="432,288,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="75"/>
<ListView HorizontalAlignment="Left" Height="273" Margin="10,10,0,0" VerticalAlignment="Top" Width="497">
<ListView.View>
<GridView>
<GridViewColumn/>
</GridView>
</ListView.View>
</ListView>
</Grid>
If you choose to use Grid layout you should try to avoid placing objects via Margin. Margin should be used to create buffer around an object, not move it to a specific point in the window. Use the layout manager's power to your advantage!
Here is a Grid example that does what you are looking for.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListView Grid.Row="0" />
<Button Grid.Row="1" HorizontalAlignment="Right" Content="Push Me" />
</Grid>
I would also read up on Layout Manager in WPF. There are several; each having its own advantages & disadvantages.
Here is a DockPanel version.
<DockPanel>
<Button DockPanel.Dock="Bottom" HorizontalAlignment="Right" Content="Push Me" />
<ListView />
</DockPanel>
To create your buffer between the button and the window chrome you could do a few different things:
<Grid Margin="10"> will apply a 10 pixel space between all content and the window chrome on all side.
<Grid Margin="0,0,10,10"> would indent all content, but only on the right & bottom.
<Grid Margin="10,0,10,10"> indents all around, except the top (I commonly do this one, with a different margin value).
<Button Margin="0,0,10,10"> would indent only the button from the chrome (this is the direct answer to your comment question).
Replace the Grid above with DockPanel for the second example, or whatever other Layout Manager you are using.
A usability side note: Your confirmation buttons (I'm assuming your button will be an Ok/Cancel type button) should not be indented differently from the rest of your content. All controls that butt up against the right margin should do so at the same point (i.e., you can draw a vertical line down the right side of them all).
So, using your question's example: your button should not be indented 10 pixels to the right while your list box is not. Keeping things lined up will improve the overall look to your application.
(this ends my "usability and look-and-feel is important" side note) :)
<Button VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5"/>
Some code example will help. Try using the alignment in xaml for your button as shown below. Ensure that the margins on the button are 0.
<Button Margin="0" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
Looking at the sample code, it is your margins and the alignment you have that are probably causing that.
Just some pointers that may help. Instead of using large margins to align the controls, I find it much easier to work with Column and Row definitions on the grid. This way you can align your controls using the grid and they will size properly as you resize your window. I attached an example in hopes it helps in your new adventures with WPF!
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="Version Date" Margin="3" VerticalAlignment="Center"/>
<TextBlock Grid.Column="0" Grid.Row="1" Text="{Binding DateSubmitted}" Margin="3"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="Report" Margin="3" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding ReportName}" Margin="3"/>
</Grid>

WPF Resize Window proportionally ie. No stretching or distorting?

I have a WPF Window which contains a Grid. It's set up to look like a Checkers board, so I need the squares of the grid to stay square when the window is resized.
I've tried many things but nothing seems to work. I hope it's just a matter of getting the right attribute, and not something complicated, but I need it to resize proportionally either way.
I'm also not sure if this should happen in the Grid or in the Window. I would assume the Window because that's the controller for resizing, but I could be wrong.
Any suggestions?
xaml for Window:
<Window x:Class="TicTacToeClient.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TicTacToeClient"
Title="Mini-Checkers V1.1" Height="600" Width="600"
MinHeight="200" MinWidth="200" MaxHeight="600" MaxWidth="600" >
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="Game">
<MenuItem Header="Set Ip Address" Name="IPAddressMenuItem"/>
<MenuItem Header="Set Name" Name="SetNameMenuItem"/>
</MenuItem>
</Menu>
<TextBlock DockPanel.Dock="Bottom" Text ="Status: " Name="GameStatusBar" />
<local:TicTacToeBoard x:Name="GameBoard" />
</DockPanel>
xaml for Grid:
<UserControl x:Class="TicTacToeClient.TicTacToeBoard"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="600">
<Grid Name="MainGrid">
<Grid.RowDefinitions>
....
I would suggest DataBinding the Width of your Grid to the Height (or vice-versa). This will make sure that it always grows proportionally. Something as simple as this should work:
<Grid x:Name="Checkerboard" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Width="{Binding RelativeSource={RelativeSource Self}} Path=ActualHeight}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- Grid Contents -->
</Grid>
And if you want your cells to all remain square, just make sure they're all * sized, so they will be spread out equally.
Alternatively, you can put yor grid inside a Viewbox with Stretch="Uniform"
You can try enclosing yourGameBoard in a ViewBox with Stretch Property set to Uniform and StretchDirection set to Both. like this. It wont keep the Form's Aspect ratio uniform but will keep your GameBoard Proportions Uniform.
<Viewbox Stretch="Uniform" StretchDirection="Both">
<local:TicTacToeBoard x:Name="GameBoard" />
</Viewbox>

how do i get my datagrid to grow with the window and maintain margins?

Everything about my layout will flow with the resizing of the main window. The problem I'm facing is that as you can see, the datagrid goes off the screen. If you maximize the window, the datagrid will resize with the window, but continue to go off the screen. How do I get it to maintain its margin of 20 with it's parent grid?
<Grid>
<StackPanel Orientation="Vertical">
<TextBox Height="170" Name="txtSQL" VerticalAlignment="Top" AcceptsReturn="True" TextWrapping="Wrap" Margin="20"/>
<Button Content="Run!" Height="23" HorizontalAlignment="Left" Name="btnRun" VerticalAlignment="Top" Margin="20,0,0,0" Width="75" Click="btnRun_Click" />
<Grid>
<my:DataGrid Name="dgResults" VerticalAlignment="Top" Margin="20" />
</Grid>
</StackPanel>
</Grid>
UPDATE:
Just to be more specific. The effect I'm trying to accomplish here is this:
When the window first loads, you are presented with a blank datagrid, so it's only about 15 pixels high. When you run the query, it will populate the datagrid by reassigning the itemssource. As of now, when you do that, if the data exceeds the window size, it will go off the bottom of the screen. I need it to only expand to the bottom of the window then enable the scrollbar. I can do this just by wrapping it in a scrollviewer im sure. However, when the window is resized, the datagrid needs to resize with it.
I'm wondering if the setup might have something to do with it. The form is actually a wpf page being displayed in a frame.
UPDATE:
<Page x:Class="Hold_Database___Prototype_1.Views.SQL"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="304" d:DesignWidth="732"
Title="SQL" xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit" AllowDrop="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="23" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Height="170" Name="txtSQL" VerticalAlignment="Top" AcceptsReturn="True" TextWrapping="Wrap" Margin="20" Grid.Row="0"/>
<Button Content="Run!" Height="23" HorizontalAlignment="Left" Name="btnRun" VerticalAlignment="Top"
Margin="20,0,0,0" Width="75" Grid.Row="1" Click="btnRun_Click" />
<DockPanel Grid.Row="2">
<my:DataGrid Name="dgResults" Margin="20" />
</DockPanel>
</Grid>
</Page>
What is the dock panel for in this example?
Try putting the DataGrid directly in the cell with no stackpanel. If you are setting the button height then set set grid to auto.
Also, why give so much space to the text?
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Height="170" Name="txtSQL" VerticalAlignment="Top" AcceptsReturn="True" TextWrapping="Wrap" Margin="20" Grid.Row="0"/>
<Button Content="Run!" Height="23" HorizontalAlignment="Left" Name="btnRun" VerticalAlignment="Top"
Margin="20,0,0,0" Width="75" Grid.Row="1" Click="btnRun_Click" />
<my:DataGrid Grid.Row="2" <my:DataGrid Name="dgResults" Margin="20" />
Then also set HorizontalAlignment, VerticleAlignment, HorizontalContentAlignment, and VerticalContentAlignment = stretch
Your Grid is drawn off screen without a scroll bar because you are using a StackPanel. Care must be taken when using StackPanel - it is the most simplistic of all WPF Panel derived classes since its MeasureOverride calls Measure for all of its children with a size of double.PositiveInifity regardless of how much space the panel actually has available. Even a ScrollViewer will not help you with a StackPanel (the ScrollBar will be shown, but you won't be able to move it).
For example, consider a Window 350 in height and width, and a single Button as its content which is 500 in both height and width:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="350">
<StackPanel>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Button Content="Hello" Height="500" Width="500" />
</ScrollViewer>
</StackPanel>
</Window>
Similar to your example, the Button here is drawn off screen in both the vertical and horizontal directions and a non-functional scroll bar will be present. If we change the panel to one which respects the size of its given area (e.g. DockPanel):
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<ScrollViewer>
<Button Content="Hello" Height="500" />
</ScrollViewer>
</DockPanel>
</Window>
then scroll bars appear which are functional and hence allow the content off screen to be shown by scrolling.
Hope this helps!
What I have done was do define the horizontal and vertical alignments to "Stretch" respectively at the control you want (your DataGrid) to take up the size based on the window being resized.

Layout two controls on a line in a stretchable WPF window

Here's a fairly common UI pattern: Text box that contains a path to the left, and a Browse button to the right of it. If the window resizes, the button stays to the right, but the text box stretches to reveal more/less of the path. So in the good old days of anchors, the button would be anchored to the right and the text box would be anchored both left and right.
Trying to replicate this in WPF seems to be worryingly difficult.
If I create a new window, it comes with a Grid layout by default. I place my text box to the left and size it appropriately, then place the button to its right. HorizontalAlignment for the text box is Stretch and for the button it is Right.
In my mind, this works as described, but in real life the text box doesn't resize at all, but instead tries to center itself in the window, while the button acts as expected. What gives?
Here is my XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="241" d:DesignWidth="414" SizeToContent="WidthAndHeight">
<Grid>
<TextBox Height="23" HorizontalAlignment="Stretch" Name="textBox1" VerticalAlignment="Top" Margin="12,11,101,0" />
<Button Content="Button" Height="23" HorizontalAlignment="Right" Margin="0,11,12,0" Name="button1" VerticalAlignment="Top" Width="75" />
</Grid>
</Window>
You would create another GridControl with two columns, one with a fixed width for Browse button and another one for the TextBox.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" />
<Button Grid.Column="1" />
</Grid>
You can use a DockPanel and set LastChildFill property to true to ensure that the textbox uses all the available space:
<DockPanel LastChildFill="true">
<Button DockPanel.Dock="Right">Browse</Button>
<TextBox>Content</TextBox>
</DockPanel>

Categories

Resources