How to prevent Labels on bottom of window from disappearing when resizing? - wpf

Basically I have a window is that SizeToContent="WidthAndHeight" and I have a Label positioned on the bottom. When resizing the window the label disappears. Unless I make the window a lot bigger.
I have the following XAML code:
<Window x:Class="DateKeeper.View.Test"
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:DateKeeper.View"
mc:Ignorable="d"
Title="Test" SizeToContent="WidthAndHeight"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label x:Name="label" Content="Label" HorizontalAlignment="Left" VerticalAlignment="Bottom" Grid.Column="0" Grid.Row="1" FontSize="36"/>
<TextBlock x:Name="textBlock" Grid.Column="1" Text="TextBlock" VerticalAlignment="Bottom" Grid.Row="1" FontSize="36"/>
</Grid>
</Window>
And here are the pictures:
Before Resizing
After resizing

SizeToWidthAndHeight sets the window's initial size. It doesn't prevent the user from resizing the window.
ResizeMode="NoResize" will prevent all resizing. If you want to set a minimum size and allow the window to be sized larger than that, you can't do that in pure XAML.
However, you can use that initial size as a minimum width and height with some simple code in a loaded handler, like so:
<Window
x:Class="DateKeeper.View.Test"
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:DateKeeper.View"
mc:Ignorable="d"
Title="Test"
SizeToContent="WidthAndHeight"
Loaded="Window_Loaded"
>
Test.xaml.cs (or whatever you call the codebehind for the above Window):
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MinWidth = ActualWidth;
MinHeight = ActualHeight;
}
You could also write an attached property that would do the same thing.
Update
This pure-XAML approach with Mode=OneTime seems promising:
<Window
...
SizeToContent="WidthAndHeight"
MinHeight="{Binding ActualHeight, RelativeSource={RelativeSource Self}, Mode=OneTime, PresentationTraceSources.TraceLevel=High}"
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource Self}, Mode=OneTime}"
...
...but in trace output, we see that it gets the values of ActualHeight and ActualWidth very early on, before the window is sized to its content, perhaps before then actual UI window object is even created -- at a point when the actual width and height are both reported as zero.

You have 50% now
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Label x:Name="label" Content="Label" FontSize="36"
Grid.Row="1" Grid.Column="0" VerticalAlignment="Bottom" HorizontalAlignment="Left" />
<TextBlock x:Name="textBlock" Text="TextBlock" FontSize="36"
Grid.Row="1" Grid.Column="1" VerticalAlignment="Bottom"/>
</Grid>

Not sure what you are trying to create, but three things:
The elements are losing visibility because they are going off of the screen because they are running out of room
Your layout puts both text elements in the second row of the Grid
a. The elements will only have 50% of the available height to render
b. FontSize and Margins/Padding will further offset this
You have two different text element types (Label and TextBlock)
a. Both have different Margin/Padding values
b. The different layout values will result in different levels of visibility
If you don't want the elements to lose visibility, you need to set a minimum size of the Window (e.g. 325x150).

Related

How can I automatically resize objects that are in a grid?

So I have recently started learning more C# and I am currently trying to create a GUI. I so far have a title and a text box that looks like this:
https://i.imgur.com/BvpkQ3U.png
Yes, this looks fine, it's not the problem. The problem is when you open the window (by debugging it) the window is set to the size of which it looks like on the preview. Which is fine. But, when I maximize it the objects inside of the window do not get larger. They stay at the same size. Which looks like this:
BEFORE:
https://i.imgur.com/NuGTDwf.png
AFTER:
https://i.imgur.com/pVy2aYk.png
How can I make it so the objects inside of the window get larger just like the window itself does?
MainWindow.xaml:
<Window x:Name="THE_GUI" x:Class="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:GUI"
mc:Ignorable="d"
Title="GUI" Height="450" Width="800" Foreground="Black" WindowStyle="SingleBorderWindow">
<Grid>
<TextBlock x:Name="GUI_TITLE2" HorizontalAlignment="Center" Margin="0,10,0,0" Text="TITLE" TextWrapping="Wrap" VerticalAlignment="Top" Height="50" Width="125" FontSize="18"/>
<TextBox HorizontalAlignment="Left" Margin="41,35,0,0" Text="TextBox" TextWrapping="Wrap" VerticalAlignment="Top" Width="204" Height="375" IsReadOnly="True"/>
</Grid>
</Window>
If you require more code I can provide it
Thanks! :)
PS
I did see this question: WPF: How can I have controls in a grid automatically resize when the grid is resized? but it doesn't help me at all.
Do not set Height & Width of controls (TextBlock/TextBox) if you want them to resize. Also you are using a plain grid with no Row/Columns so WPF will not know how to scale your GUI.
You need to read about different type of Panels/Containers available in WPF and how to use them to Lay your Controls.
Check: StackPanel, WrapPanel, DockPanel. For Grid read about RowDefinitions and Columndefinitions. Read the WildCard height and width assignment.
As suggested by Prateek also, simply putting controls under grid won't work. If you want to go with grid control, then please have row and columns created to align the controls. I've updated your code and here it is:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="13*"/>
<RowDefinition Height="87*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="30*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="1"
x:Name="GUI_TITLE2" HorizontalAlignment="Stretch"
Text="TITLE" TextWrapping="Wrap" VerticalAlignment="Stretch"
FontSize="18"/>
<TextBox Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Stretch" Text="TextBox" TextWrapping="Wrap"
VerticalAlignment="Stretch" IsReadOnly="True"/>
</Grid>

Window Auto sizing when adding grid row via button [duplicate]

I have a dialog containing 2 TextBlocks, a Progress Bar and a cancel Button.
Here is the XAML:
<Window x:Class="WpfApplication4.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:WpfApplication4"
mc:Ignorable="d"
Title="MainWindow" Height="Auto" Width="200">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="txtFirst" Grid.Row="0" Margin="5" TextWrapping="Wrap">This is a really really really really long string that wraps</TextBlock>
<TextBlock x:Name="txtSecond" Grid.Row="1" Margin="5" Text="A Shorter string" TextWrapping="Wrap" MaxWidth="200"/>
<ProgressBar x:Name="prgProgress" Grid.Row="2" Margin="5" Height="20" />
<Button x:Name="btnCancel" Grid.Row="3" Margin="5" Height="25" Width="50"/>
</Grid>
</Window>
I would like the Window not to have a fixed height but auto adjust its height based on the size of its children and no more, but can’t see a way to do this. At the moment when I don’t assign anything to the Window’s height, it seems to adopt a height that is much bigger that the content.
Not sure why, or where it gets height value from? If I set Windows Height = “Auto” I get the same thing. All the heights for the RowDefinitions are set to “Auto”, which I take to mean ‘set row height to be row child height’.
You need to use SizeToContent property, check the msdn link.
Example:
<Window 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"
…
SizeToContent="WidthAndHeight">

ItemsControl-wrapping the contents inside the window

I am using an ItemsControl inside a window in WPF. The itemscontrol is bound with a collection and the collection is a group of view models(user controls). My problem - the view is going beyond the current window as a result of many view models in the collection. I tried many things to handle it with a scroll bar but no use. Any suggestions? The question really is how to contain the itemscontrol within a window(with scrolling)?
The XAML below
<Window x:Class="WpfApplicationTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WpfApplicationTest"
Title="MainWindow" Height="350" Width="525">
<Grid Height="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ItemsControl Grid.Row="0" Grid.Column="0" ItemsSource="{Binding UserControlCollection}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button Content="OK" Width="100" Margin="3" />
<Button Content="Cancel" Width="100" Margin="3" />
</StackPanel>
</Grid>
Wrap your ItemsControl in a ScrollViewer
Update: in your example, also set row height to * if it won't scale correctly.
In addition to #Bas's answer, set your MaxHeight and MinHeight properties to your window dimensions. You can either use the hard-coded numbers you have in the example, or create a binding to Window.ActualHeight/ActualWidth.

Why is there no vertical scroll bar for this listbox

Given the following XMAL why is no vertical scrollbar for the ListBox which is bound to an ObservableCollection of 100 strings. If I change the height of the second row from * to something fixed like 500 then a scrollbar appears, but obviously i want the row height to be what ever is available (which is what I understand * to mean)
<UserControl x:Class="SimpleStack.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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<DataTemplate x:Key="ListBoxItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Place holder"/><TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="Azure">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="The Text" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"/>
<ListBox ItemsSource="{Binding ListOfNumbers}" Grid.Row="1" Grid.Column="0"
ItemTemplate="{StaticResource ListBoxItemTemplate}"/>
<TextBlock Text="Place Holder" Grid.Row="1" Grid.Column="1"/>
</Grid>
</UserControl>
The * row height is in fact "everything else available" (if you have multiple *s, it would divy that up). I am guessing that your actual issue is that "whatever is available" is infinite. Most likely the usercontrol is being given an unlimited amount of space, so it is expanding to take up as much room as it needs. Make sure you're limiting your usercontrol to the actual visible space and your listbox should get its scrollbar.
My understanding is that because of the measure/arrange layout system you are essentially telling the ListBox it can have all the vertical space it needs without being constrained. The internal ScrollViewer in the default ListBox template is therefore never constrained to trigger the scroll bar to appear.
I can see two ways to fix this for your situation:
-Specify ScrollViewer.VerticalScrollBarVisibility="Visible" on the ListBox to force the internal ScrollViewer to always show the scroll bar.
-Use an actual ScrollViewer to contain the ListBox and let that provide the scrolling capability instead of the one in the internal ListBox (you might have to tweak padding and borders to get it to look right):
<ScrollViewer Grid.Row="1" Grid.Column="0">
<ListBox ItemsSource="{Binding ListOfNumbers}"
ItemTemplate="{StaticResource ListBoxItemTemplate}"/>
</ScrollViewer>
I would prefer the second way because it would only show the vertical scroll bar if it was really necessary.

Centering a WPF control

I have a window where I add a new UserControl to (with an image), I simply want to center the control in the middle of the screen (both vertically and horizontally). I can only get the vertical one to work. I'm gonna swap content in the DockPanel from my CodeBehind and want to show this startup screen before I start doing my slideshow UI, this means that the content is set from the CodeBehind.
My Window:
<Window x:Class="GreenWebPlayerWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="512" Width="853" WindowStyle="None" WindowState="Maximized" WindowStartupLocation="CenterScreen">
<DockPanel Width="Auto" Height="Auto" Name="TransitionContainer" Background="Black" Margin="0" LastChildFill="True"></DockPanel>
</Window>
My UserControl:
<UserControl x:Class="GreenWebPlayerWPF.FrontPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel Background="Black">
<Image Name="image1" Stretch="None" Source="/GreenWebPlayerWPF;component/gw.png" />
</DockPanel>
</UserControl>
Please note that I'm using maximized/full screen.
Use a Grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Replace with your UserControl -->
<Button Content="Foo" Grid.Column="1" Grid.Row="1"/>
</Grid>
You can dock it inside your DockPanel (if you must have a DockPanel there) to stretch. And, of course, while the above is all markup, you can just as easily create such a grid from code.
I keep running into this problem when trying to center elements on the page.
The problem with the StackPanel is that HorizontalAlignment has no effect when the Orientation is Horizontal and VerticalAlignment no effect when Orientation is Vertical. So you keep banging your head trying to set values with no effect. It is not illogical that it works this way but it would be good if this was reported as an error.
The solution I found is to have two imbricated StackPanels one centered horizontally and the other vertically as shown below. Finding the size of the parent is needed to size the intermediate panel otherwise it would be flat and its content hidden - an absolute value would work as well. Although not a panacea itis a bit less verbose than using a grid.
<StackPanel Background="Bisque" Orientation="Vertical" Width="300" Height="300" >
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=StackPanel}, Path=ActualHeight}">
<StackPanel VerticalAlignment="Center" Width="200" Height="60" Background="Blue">
</StackPanel>
</StackPanel>
</StackPanel>
It's quite an old one, but centring a control is now as simple as:
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Height="350" Width="600">
<TextBox />
</StackPanel>
</Grid>

Resources