XAML element fill all remaining space - c#

I have a WPF application and I'm trying to get the elements positioned correctly. There are just four elements, so it should be pretty straight-forward, but I just can't get it working.
One wrinkle is that the window resizes itself to (about) the size of the desktop window when it appears, so it doesn't have a fixed size.
The elements are supposed to be stacked from top to bottom, so a Stack Panel seemed natural. But The third element has to take up all the remaining space that the top two and bottom ones don't. No matter what I tried, it either took up too much space, or too little. I could only seem to get it working if I gave it a concrete pixel size which, as explained above, won't work.
The latest thing I've tried is a Dock Panel. While it looks correct in the Visual Studio designer, when executed, the third element--a Canvas--completely covers the bottom element.
My XAML:
<DockPanel>
<Button x:Name="btnClose" DockPanel.Dock="Top" Content="X"
HorizontalAlignment="Right" Margin="0,5,5,0" VerticalAlignment="Top"
Width="Auto" Height="Auto" Background="Black"
Foreground="White" Click="btnClose_Click"/>
<Label x:Name="lblTitle" DockPanel.Dock="Top" Content="My Title"
HorizontalAlignment="Center" VerticalAlignment="Top" Width="Auto"
Foreground="White" FontWeight="Bold" FontSize="22"/>
<Label x:Name="lblControls" DockPanel.Dock="Bottom" Content="Placeholder"
HorizontalAlignment="Center" VerticalAlignment="Bottom" Width="Auto"
Height="Auto" Foreground="White" FontWeight="Bold" FontSize="22"/>
<Border x:Name="CanvasBorder" BorderBrush="White" BorderThickness="5" >
<Canvas x:Name="cvsChart" Grid.Row="0" HorizontalAlignment="Stretch"
VerticalAlignment="Top" Width="Auto">
</Canvas>
</Border>
</DockPanel>
Any idea about how to get that Canvas to stretch and fill all the space the other three don't take?
UPDATE
Since #Peter Duniho pretty much proved to me that the code worked, I tried an experiment and removed the resizing code I have in place for when the window appears. Taking it out, the window appears absolutely correctly. This is what I do to resize it to (mostly) the desktop size:
public const int WINDOW_OFFSET = 10;
...
int screenWidth = (int)System.Windows.SystemParameters.PrimaryScreenWidth;
int screenHeight = (int)System.Windows.SystemParameters.PrimaryScreenHeight;
// center this window in desktop
Width = screenWidth - WINDOW_OFFSET;
Height = screenHeight - WINDOW_OFFSET;
Left = WINDOW_OFFSET/2;
Top = WINDOW_OFFSET/2;
So I did some poking around, and found a comment here on the 'Stack that said to get the WorkArea instead of the PrimaryScreenHeight. I tried that and voila!, the whole application window appears.
int screenWidth = (int)System.Windows.SystemParameters.WorkArea.Width;
int screenHeight = (int)System.Windows.SystemParameters.WorkArea.Height;
As it turns out, the bottom row was displaying, I just couldn't see it because it appeared below the bottom of the screen. Now I can see it, and I'm back to development heaven!
Thanks to everyone for their input!

There are a number of possible approaches to this. One of the most straightforward is to contain your elements in a Grid and set all but the third row height to Auto:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button x:Name="btnClose" Content="X" Grid.Row="0"
HorizontalAlignment="Right" Margin="0,5,5,0" VerticalAlignment="Top"
Width="Auto" Height="Auto" Background="Black"
Foreground="White" Click="btnClose_Click"/>
<Label x:Name="lblTitle" Content="My Title" Grid.Row="1"
HorizontalAlignment="Center" VerticalAlignment="Top" Width="Auto"
Foreground="White" FontWeight="Bold" FontSize="22"/>
<Label x:Name="lblControls" Content="Placeholder" Grid.Row="3"
HorizontalAlignment="Center" VerticalAlignment="Bottom" Width="Auto"
Height="Auto" Foreground="White" FontWeight="Bold" FontSize="22"/>
<Border x:Name="CanvasBorder" BorderBrush="White" BorderThickness="5" Grid.Row="2">
<Canvas x:Name="cvsChart" Grid.Row="0" HorizontalAlignment="Stretch"
VerticalAlignment="Top" Width="Auto">
</Canvas>
</Border>
</Grid>
The default setting for a grid's row definition height is "*", which says to distribute all of the remaining space among all the rows with that setting. With only one row using that setting, it gets all of the leftover space.
This produces a window that looks like this:
(I set the window background to Gray so that your white text and border would be visible.)
Another option would in fact be to use DockPanel. It appears to me that the main problem in your attempt is that you set the lblControls element to DockPanel.Dock="Bottom" when it should be Top instead. When I change it to Top, it seems to work fine for me.
Based on your comment below, it seems you actually did want lblControls to be set to DockPanel.Dock="Bottom", and in fact the code you posted seems to also do what you want. It's not clear to me what is different from what the code you posted does and what you want it to do. It would be better if you would provide a good Minimal, Complete, and Verifiable code example that reliably reproduces the problem.

Remove the vertical alignment of the Canvas

Related

UWP AutoCompleteBox in ContentDialog not sizing correctly - text area larger than drawn

I have an AutoCompleteTextBox in UWP is exhibiting a really odd behavior, and I can't figure out what's causing it. The TextBox is in a Grid, but the user can type past the bounds of the TextBox, so the first and last characters of each line are hidden behind the surrounding border. I've taken some screenshots to hopefully make this make more sense, as it's difficult to describe.
I've tried everything I can think of, but can't seem to get it to stop doing this. The only effect I had at all was in changing the HorizontalAlignment of the TextBox. Originally it was Stretch, and only the right side of the TextBox had cutoff letters. When I changed it to Center, it divided the cut-off section between both the left and right.
Does anybody have any ideas as to what's going on?
In the 1st picture, the actual TextBox area is defined by the box on the far outer edges of the ContentDialog [with the drag handles left of the (116)].
TextBox in VS Designer
In the second picture, the letters typed in the TextBox are 2 W's. If you look closely, you can just see the very right of the 1st W to the left of the full W there.
TextBox during execution
XAML:
<ContentDialog
x:Class="FlipPanelTest2.ComposeTweet"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FlipPanelTest2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
RequestedTheme="Dark"
Title="{Binding SendTo}"
Foreground="Gray"
Width="600"
PrimaryButtonText="Cancel"
SecondaryButtonText="Tweet!"
SecondaryButtonStyle="{StaticResource TweetContentDialogButtonStyle}"
PrimaryButtonStyle="{StaticResource CancelButtonStyle}"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
SecondaryButtonClick="ContentDialog_SecondaryButtonClick">
<Grid Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox x:Name="tweetText" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Stretch" Background="White" TextWrapping="Wrap" Margin="2" TextChanged="TextBox_TextChanged" MaxHeight="180" MinHeight="112" Width="540" />
<StackPanel x:Name="characterCount" Orientation="Horizontal" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center">
<TextBlock x:Name="currentChars" HorizontalAlignment="Right" Grid.Row="1" FontSize="10" Text="{Binding TweetCharacters}" />
<TextBlock x:Name="charsDivider" HorizontalAlignment="Right" Grid.Row="1" FontSize="10" Text="/" />
<TextBlock x:Name="maxChars" HorizontalAlignment="Right" Grid.Row="1" FontSize="10" Text="{Binding MaxCharacters}" />
</StackPanel>
</Grid>
Well some more searching found the answer apparently. I hadn't thought to search for a max size on the ContentDialog, hence the reason I didn't find this before. Providing a link to the answer though for future people to use:
Quoted from ContentDialog max width:
In your App.xaml, try setting the ContentDialogMaxWidth to say, 800.
The default is 548. You might want to increase the height too.
<Application.Resources>
<x:Double x:Key="ContentDialogMaxWidth">800</x:Double>
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
</Application.Resources>
ContentDialog max width
It's the last answer listed there, for some reason not the accepted answer. :)

Layout cycle detected error with two progressRings

I want to create a custom user control with two grids in which I want to load images and until images are loaded I want to show the progressRing control. The problem occurs when I add a second ProgressRing. My XAML looks like this:
<Grid Margin="0,0,0,21" Background="{ThemeResource PhoneAccentBrush}">
<Grid x:Name="leftImage" Margin="10" Width="190" Height="190"
HorizontalAlignment="Left">
<Image x:Name="imageHolderLeft" x:FieldModifier="public" Width="180"
Height="180" ImageFailed="imageHolderLeft_ImageFailed"
ImageOpened="imageHolderLeft_ImageOpened"/>
<Grid>
<ProgressRing x:Name="waitImageLeft" IsActive="True"
VerticalAlignment="Center" HorizontalAlignment="Center"
Background="Transparent"
Foreground="{ThemeResource AppBarBackgroundThemeBrush}"/>
</Grid>
</Grid>
<Grid x:Name="rightImage" Margin="10" Width="190" Height="190"
HorizontalAlignment="Right">
<Image x:Name="imageHolderRight" x:FieldModifier="public" Width="180"
Height="180" ImageOpened="imageHolderRight_ImageOpened"
ImageFailed="imageHolderRight_ImageFailed"/>
<Grid>
<ProgressRing x:Name="waitImageRight" IsActive="True"
VerticalAlignment="Center" HorizontalAlignment="Center"
Background="Transparent"
Foreground="{ThemeResource AppBarBackgroundThemeBrush}"/>
</Grid>
</Grid>
</Grid>
So when I comment out one ProgressRing it works fine, but when there are two of them my program crashes with the following error: Layout cycle detected. Layout could not complete
Does anyone knows why?
Thanks :)
This error indicates that the layout of an element depends on other elements that indirectly depend on the original element. Windows was not able to figure out the overall layout... Much like an infinite loop or infinite recursion.
In your case the cause probably relates to the alignments and sizes. You should be able to solve the problem by simplifying the layout. Keep the outer Grid but add 5 ColumnDefinitions, the middle one having width * and the other ones width Auto. Get rid of the other 4 Grids. Instead, put the two images and progress rings directly into the main Grid in columns number 0, 1, 3, and 4 (using the Grid.Column attached property). Put the desired sizes on the Width and Height properties of the images and progress rings, not on the Grid.

WPF How do I make a Border width expand to fill available space in a DockPanel

I have a custom control ButtonRow which will end up going into a different control.
It is very simple, it has one Border, on label and one button.
I need to make it so that the border will extend its width to fill up to where the button is.
This is not happening as you can see in the below image:
The XAML can be found below. I have tried fiddling about with the horizontal alignment of both he label and the border, but they will only ever re-size to fit the text content of the label.
I know there are existing question with very similar problems and names, but none have needed to do quite the same thing or have helped me solve my problem.
I have tried using a StackPanel in horizontal alignment but all it did was make the button go next to the border.
How can I make the border expand to fill the available space?
<Grid>
<DockPanel Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="dockPanel1" VerticalAlignment="Top" Width="Auto">
<Border BorderBrush="#FFDADFE1" Background="#FFECF0F1" BorderThickness="1" Height="20" Name="bdrFilter" HorizontalAlignment="Stretch">
<Label Content="Filter..." FontStyle="Italic" Foreground="#FF6C7A89" Height="20" Name="lblFilter" Padding="5,0" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" />
</Border>
<Button Style="{StaticResource FlatButtonStyle}" Content="+" Height="20" HorizontalAlignment="Right" Name="btnAddFilter" VerticalAlignment="Top" Width="20" Foreground="#FF6C7A89" ForceCursor="True" BorderBrush="{x:Null}" />
</DockPanel>
</Grid>
(The button style does not affect its alignment or any other relevant properties)
A DockPanel is not the correct Panel to use for this requirement... like a StackPanel, it does not resize its contents. Instead, just use a regular Grid (which also uses less resources than a DockPanel):
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border BorderBrush="#FFDADFE1" Background="#FFECF0F1" BorderThickness="1"
Height="20" Name="bdrFilter" VerticalAlignment="Top">
<Label Content="Filter..." FontStyle="Italic" Foreground="#FF6C7A89"
Height="20" Name="lblFilter" Padding="5,0" />
</Border>
<Button Grid.Column="1" Content="+" Height="20" HorizontalAlignment="Right"
Name="btnAddFilter" VerticalAlignment="Top" Width="20" Foreground="#FF6C7A89"
ForceCursor="True" BorderBrush="{x:Null}" />
</Grid>
Please see the Panels Overview page on MSDN for more information about the different Panels in WPF.
This might help you out. Setting LastChildFill=True inside a DockPanel does exactly what the name suggests.

WPF Facing App window size on different resolution

I have a WPF application. To make the full screen visible on all screen sizes, I have implemented MinHeight, MinWidth & HorizontalAlignment="Stretch" VerticalAlignment="Stretch" in Window & Containers too. I am facing some problems when the app runs on Lower Resolution screens. The window gets cut from the right side of the screen - this doesn't show Min, Max, Close btns also on top right.
If I add layout code in then the window is proper in all resolutions, but it makes blank space above the Menubar and below end. On removing , their is no space and all is well, but right side gets cut in Low Resolution screens. And with ViewBox, space above and below the layout. My XML code is like follows :
CODE UPDATED
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- MENU BAR -->
<Menu Grid.Row="0" x:Name="myMnus" VerticalAlignment="Top" Cursor="Hand" HorizontalAlignment="Stretch" IsMainMenu="True" Grid.ColumnSpan="2">
.............
</Menu>
<ToolBarTray HorizontalAlignment="Stretch" Background="White" Margin="0,19,114,0" VerticalAlignment="Top" Grid.ColumnSpan="2" >
..............
<ToolBarTray>
<TabControl Grid.Row="1" Name="tabControl1" HorizontalAlignment="Left" Margin="0,3,0,0" VerticalAlignment="Top"
TabStripPlacement="Bottom" Grid.RowSpan="2" BorderThickness="4,25,4,1" FontSize="13">
</TabControl>
<TabControl Grid.Row="2" Name="tabControl4" HorizontalAlignment="Left" Margin="0,323,0,0" VerticalAlignment="Stretch"
TabStripPlacement="Bottom" BorderThickness="4,25,4,1" FontSize="13" Background="White" Width="227">
</TabControl>
<TabControl TabStripPlacement="Bottom" MinHeight="415" MinWidth="480" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="1" Grid.Column="1" Name="tabChildContainer" Margin="227,3,207,0" BorderThickness="4,25,4,1" Grid.RowSpan="2" >
</TabControl>
</Grid>
I thought by using Stretch in HorizontalAlignment and VerticalAlignment along with MinWidth and MinHeight, that it would occupy all available space horizontally and Vertically. But tabChildContainer TabControl doesn't go to the right end corner which it should go based on the code.
This is where your problem starts:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="762.976"/>
<ColumnDefinition Width="751.024"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
Anytime that you set exact pixel sizes in your UI, you're asking for exactly these kinds of problems. Setting exact sizes for sections of your application was more of a WinForms thing... WPF has numerous controls that can resize your content for you... you're using one, the Grid... just incorrectly.
Secondly, it is very unusual to use a ViewBox on your whole UI... it is not going to help you. Your best bet is to simply remove it and all of your hard-coded dimensions and make full use of the "*" and "Auto" values in your Grid. When the controls resize themselves (or a Grid resizes them) in this way, it really doesn't matter what resolution a user is using.

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>

Categories

Resources