Why the height is incorrect? - wpf

I have a simple WPF form with next XAML
<Window x:Class="ReikartzDataConverter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="650" Width="800">
<Grid Width="780" Height="650">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="500"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Process information" Height="28" HorizontalAlignment="Left" Margin="0,20,0,0" Name="label1" VerticalAlignment="Top" Width="235" />
<DataGrid Grid.Row="1" Width="780" Height="500" Name="paysTable">
</DataGrid>
<Label Grid.Row="2" Height="28" Name="lblError" VerticalAlignment="Top" Visibility="Hidden" Foreground="OrangeRed" FontWeight="Bold" FontSize="12" />
<Button Grid.Row="3" Content="Quit" Height="23" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<Button Grid.Row="3" Content="Start" Height="23" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" />
</Grid>
</Window>
Why my 2 buttons from Grid.Row="3" are partially located out of the visible part of the window?
My window has the height="650" and my Grid also has the Height="650"
I have 4 Rows: 50, 50, 500, 50. So the last row must be located inside the window. Why is not so?

The Window Height of 650 also includes the 'chrome', i.e. the bar at the top of the window with the minimize, maximize buttons. It is a much better approach to create a layout which does not rely on a specific height. In your case, I would make the row that contains your grid auto-sized:
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
Then you can remove the height / width from your Grid, and all your other UI elements, just let the grid dictate the size of its children.

#ColinE's answer is the right approach in that you should adopt a "fluid" layout in WPF, but if you really want a fixed height for your content and you need the window to be the right size, you can use the SizeToContent property:
<Window x:Class="ReikartzDataConverter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="800"
SizeToContent="Height">
<Grid Width="780" Height="650">
...
</Grid>
</Window>
Setting SizeToContent to "Height" will make the window resize vertically so that its contents fit. Don't forget to remove the Height property from the Window declaration.

Related

WPF Forms Integration - A Problem with Grid

I am doing a feasibility study to find out whether and how we can integrate a Forms application into a WPF project.
I started with a simple example and immediately encountered a problem (here is the code):
<Window x:Class="TestFormsIntegration.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:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:local="clr-namespace:TestFormsIntegration"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Menue Bar" HorizontalContentAlignment="Center" Background="BlanchedAlmond" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<ScrollViewer x:Name="scrollViewer" Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="200" />
<RowDefinition Height="200" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<WindowsFormsHost Grid.Row="0" HorizontalAlignment="Center" Height="190" VerticalAlignment="Center" Width="250">
<wf:Button Text="Button 0" Height="180" Width="200" BackColor="Gray" />
</WindowsFormsHost>
<WindowsFormsHost Grid.Row="1" HorizontalAlignment="Center" Height="190" VerticalAlignment="Center" Width="250">
<wf:Button Text="Button 1" Height="180" Width="200" BackColor="Gray"/>
</WindowsFormsHost>
<WindowsFormsHost Grid.Row="2" HorizontalAlignment="Center" Height="190" VerticalAlignment="Center" Width="250">
<wf:Button Text="Button 2" Height="180" Width="200" BackColor="Gray" />
</WindowsFormsHost>
<WindowsFormsHost Grid.Row="3" HorizontalAlignment="Center" Height="190" VerticalAlignment="Center" Width="250">
<wf:Button Text="Button 3" Height="180" Width="200" BackColor="Gray" />
</WindowsFormsHost>
</Grid>
</ScrollViewer>
<Label Grid.Row="2" Content="Status Bar" HorizontalContentAlignment="Center" Background="Wheat" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
</Window>
In a grid with 4 rows I place 4 forms buttons. When I run the code, the inner grid crosses the boundaries and overwrites the labels at the top and bottom (indicating Menu and Status Bar) and takes up the height of the entire window.
Does anyone know this behaviour and how to fix it?
Hint: Try a larger value for height (you have Height="450"), because the sum of the height of your elements is just higher (200 * 4) and don't forget the labels.
I have found the solution here:
WindowsFormsHost ZOrder
Here I read:
In a WPF user interface, you can change the z-order of elements to control overlapping behavior. A hosted Windows Forms control is drawn in a separate HWND, so it is always drawn on top of WPF elements.
But this article also contains an answer with a solution!
You can do a little trick. When you declare an WindowsFormsHost, it's parent is first HWND component. Usually it's root window. So, clip area for controls is whole window.
But there's a way to create "intermediate" HWND item to clip WinForms area over ScrollViewer. Just place another WindowsFormsHost with ElementHost.
Thank you for your answer, ds1709.

WPF Show/Hide a set of controls

I'm working on a WPF desktop application. The MainWindow is a maximized window that has a menu with few menu items. I would like to display few controls within a groupbox on the center of the window. This groupbox contains controls depending on the menu item clicked. So the size of the groupbox should not be static. Is this possible?
Thanks
Try to define your XAML like this
<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" Height="350" Width="525" WindowState="Maximized">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel>
<Button Content="Click" Height="30" Width="160"/>
<Button Content="Click" Height="30" Width="160"/>
<!--<Button Content="Click" Height="30" Width="160"/>-->
</StackPanel>
</GroupBox>
<Grid Grid.Row="1">
<TextBlock FontSize="26" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center" Text="MainUserWork Panel"/>
</Grid>
</Grid>

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>

How to have filled video at top and show label at bottom. (Fill and Anchor)

In Winforms, I use Fill and Dock to achieve this.
I have a "Page" where I would like to play a video file and also show the label at the bottom. I would like the page to be able to stretch and for the video to stretch and to have the label stay at the bottom of the page.
My attempts so far always results in the video covering the label when it is played. How can this be fixed?
(Other controls in the StackPanel have been omitted)
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MediaElementExample" >
<DockPanel LastChildFill="True">
<MediaElement Source="media\numbers.wmv" Name="myMediaElement"
LoadedBehavior="Manual" UnloadedBehavior="Stop"
MediaOpened="Element_MediaOpened" MediaEnded="Element_MediaEnded"
DockPanel.Dock="Top" Margin="50" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal"
Height="30" DockPanel.Dock="Bottom" Margin="50">
<TextBlock Margin="5" VerticalAlignment="Center">
Video Label
</TextBlock>
</StackPanel>
</DockPanel>
</Page>
Solution (with thanks to Daniel May):
<Grid Height="Auto">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<MediaElement Source="media\numbers.wmv" Name="myMediaElement" LoadedBehavior="Manual" UnloadedBehavior="Stop"
MediaOpened="Element_MediaOpened" MediaEnded="Element_MediaEnded" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Height="30" Grid.Row="1">
<Button Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" />
</StackPanel>
</Grid>
You can achieve this using a Grid.
<Grid Height="300" Width="300">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<MediaElement Source="media\numbers.wmv"
Name="myMediaElement"
LoadedBehavior="Manual"
UnloadedBehavior="Stop"
MediaOpened="Element_MediaOpened"
MediaEnded="Element_MediaEnded" />
<TextBlock Margin="5"
Grid.Row="1"
VerticalAlignment="Center"
Text="Video Label" />
</Grid>
Using the Height attribute on the second RowDefinition, you force that row to size to it's contents. The preceding RowDefinition then fills the rest of the available space (in your case, your MediaElement).

XAML Controls offsetting themselves, becoming invisible in Blend and browser

I'm having a problem, visible at runtime and in Expression Blend, where the text blocks (not text boxes, buttons, or custom controls) in my layout grid keep pushing themselves outside their cells, rendering them invisible. If I touch any of their properties in Blend (such as incrementing and then decrementing one of the margins), they become visible in Blend, but still not at runtime. Below is a screenshot showing the phenomenon in Blend. You see the design guides pointed to where the control should be, but its actual location above the top of the canvas.
Controls are offset in Blend http://tinyurl.com/y9ttscf
Update:
Below I've posted the XAML, with the VisualStateGroups removed (since they add considerable complexity to the XAML and the problem manifests itself without them). The control selected above is "loginTextBlock" below.
<navigation:Page
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:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
mc:Ignorable="d" xmlns:UserControls="clr-namespace:MyClient.UserControls" xmlns:MyClient_Controls="clr-namespace:MyClient.Controls;assembly=MyClient.Controls" xmlns:controlsToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit" x:Class="MyClient.Views.Login"
d:DesignWidth="640" d:DesignHeight="480"
Title="Login"
>
<Grid x:Name="LayoutRoot">
<Grid HorizontalAlignment="Center" Margin="0,16,0,0" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="loginTextBlock" HorizontalAlignment="Center" Style="{StaticResource HeaderTextStyle}" VerticalAlignment="Center" Text="Login" Grid.ColumnSpan="2" Margin="0,8"/>
<TextBlock x:Name="usernameTextBlock" HorizontalAlignment="Right" VerticalAlignment="Center" Grid.Row="1" Text="User name:" TextWrapping="Wrap"/>
<TextBox x:Name="usernameTextBox" HorizontalAlignment="Left" Margin="8,8,0,8" VerticalAlignment="Center" Width="175" Grid.Column="1" Grid.Row="1" TextWrapping="Wrap" TabIndex="0" FontSize="16" Height="28" Padding="2"/>
<TextBlock x:Name="passwordTextBlock" HorizontalAlignment="Right" VerticalAlignment="Center" Grid.Row="2" Text="Password:" TextWrapping="Wrap"/>
<PasswordBox x:Name="passwordBox" HorizontalAlignment="Left" Margin="8,8,0,8" VerticalAlignment="Center" Width="175" Grid.Column="1" Grid.Row="2" TabIndex="1" FontSize="16" Height="28" Padding="2"/>
<Button x:Name="okButton" Height="32" HorizontalAlignment="Center" Margin="0,16,0,0" VerticalAlignment="Top" Width="96" Content="OK" Grid.Row="3" TabIndex="2" Click="okButton_Click" Grid.ColumnSpan="2"/>
<UserControls:StatusTextBlockControl x:Name="verifyingStatusTextBlockControl" Margin="8,16,8,8" VerticalAlignment="Center" Grid.Row="4" HorizontalAlignment="Center" Grid.ColumnSpan="2" Text="Verifying credentials..."/>
<MyClient_Controls:LoginAttemptsCounter x:Name="loginAttemptsCounter" HorizontalAlignment="Center" Margin="8" VerticalAlignment="Center" Grid.ColumnSpan="2" Grid.Row="5" FirstFailureMessage="Please re-enter your Windows credentials.
After 2 more failed attempts, your account will be locked." Height="30"/>
</Grid>
</Grid>
</navigation:Page>
For some reason, when my "LoginAttemptsCounter" control is in the grid (at the bottom), it was messing up the TextBlock controls. Instead, I changed my layout to wrap the grid within a StackPanel and place the LoginAttemptsCounter in the StackPanel below the grid rather than in the grid's bottom row. That has worked.
The key thing is that my custom control can't be within the same container (either the StackPanel or the Grid) as the TextBlocks.

Resources