Lesson 3 - Positioning in C# .NET WPF
In the previous lesson, The XAML language in C# .NET WPF, we went over the basics of XAML syntax in C# .NET WPF. In today's tutorial, we're going to learn all about positioning elements. This will be the last thing we go over before we start making more interesting applications.
Absolute and relative positions
In our hello-world app, our TextBlock had an absolute position. However, we also mentioned that WPF uses relative positions form elements, which we will be putting into use in this lesson. Let's take a look at the XAML code that was generated by the graphic designer when we added a TextBlock to the form.
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="91,42,0,0" Text="Hello world from forms!"/>
In WPF, we cannot place elements in an absolute position on the Grid directly, but we can do it using margins. In the example above, the graphic designer tracked our cursor while we dropped the TextBlock in the form and added the coordinates [91; 42] to a margin. In order to display it there, it had to place it in the top left of the layout. That's why the HorizontalAlignment="Left" and VerticalAlignment="Top" attributes are set. Once it did that, it set the outer margins to 91 on the left and to 42 on the top via the Margin attribute. This way, it seems like the control is at [91; 42] when in fact the only reason it is at that spot is because there is a margin around it.
Perhaps the biggest drawback of using absolute positions is that the form will not respond to resizing or aspect ratio changes. This often happens nowadays because each device has a different screen size (cellphones, tablets, PCs). The another disadvantage is that if any control increases its size, we would have to move the other ones manually to make the form function properly. This may get very complicated in larger, more complex applications.
Although we have set the TextBlock in the middle of the form, when we resize the form, the application will end up looking like this:
Adding elements at fixed positions by clicking is a very simple and fast way to get things done, but it is also the fastest way to break our forms. Because of this, no one makes forms using fixed positions.
Relative positions, unlike absolute positions, respect its surrounding controls in both the form and in the window. Now, let's edit the TextBlock XAML code so that it is centered in its parent element (the element we have nested it in). In our case, it will be in the middle of the Grid:
<TextBlock x:Name="textBlock" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Center" Text="Hello world from forms!"/>
Now, when we run the application and narrow the form vertically or expand it horizontally, the TextBlock remains centered. Needless to say that HorizontalAlignment sets the horizontal alignment and VerticalAlignment sets the vertical alignment of an element.
Margin and Padding
Every element has a margin (the outer spacing beyond its border) and padding (the inner spacing before its border). Those of you familiar with HTML will feel at home here in the following section.
We can set different values for the margin and padding for each individual side of an element or set them all the same if we want to.
Now, let's delete the TextBlock from the form and insert a button using the following XAML code:
<Button Content="My button" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Margin="100,0,0,0" Padding="0,50,0,0"/>
Your form should now look like this:
We can see that even though the button is centered, its left margin is 100. As for the padding, the top is set to 50, which is significantly larger than the other ones.
We set margin and padding values in the following order: left, top, right, bottom (separated by commas). We are also able to specify a single value, which would set every side of the margin/padding to this value. Likewise, you could also specify two values, for horizontal and vertical spacing respectively.
Note that we have specified the width of the button in the example above using the Width attribute. Doing so is a common practice with buttons. If we didn't, the button wouldn't vary in width when the text length changed.
Device Independent Pixels
We specify sizes in DIP units. DIP stands for Device Independent Pixels. At 96 DPI, which is usually the default value when you install Windows, 1 DIP has a size of 1 physical pixel on the display. Users with large monitors, like me, usually have a higher DPI, Dots Per Inch, which changes the DIP to something like 1.25 of a physical display pixel. DPI is becoming more and more important because displays vary exponentially in size. There are 2k and 4k displays on the market, which have 4 times the resolution than those that are now considered standard. If we used ordinary pixels, our applications would be hard to see on such displays. With DIPs, it would look exactly the same because WPF would scale it automatically for us.
To set the DPI in Windows, you have to right-click on the desktop and select Personalize. Then select Display in the bottom left. There, you'll be able to change the overall size of fonts and items.
You could set a higher DPI if you want and run your WPF application which will adapt to the newly set DPI (doing so will require you to log out and back in). A Windows Forms application would break or blur after such a change. GO ahead and try running some other applications, most of them won't work properly because they're still using old technology.
Now, let's talk a little bit more about positioning controls. Edit the XAML code of the button to make it look like this:
<Button Content="My button" />
The button will stretch all over the Grid:
This is the default behavior of controls. If an alignment is not specified, the Stretch value is assumed:
<Button Content="My button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
We can set the following values to the HorizontalAlignment attribute:
- Center - Aligns to center
- Left - Aligns to left
- Right - Aligns to right
- Stretch - Stretches to fill the full width
As for VerticalAlignment, the values are similar, but instead of Left and Right, we set Top or Bottom values.
Try them all out so you can get a good feel of what relative positioning looks like. Once again, all controls are aligned to the element in which they're nested, wich is referred to as the parent element.
The height and width of elements
To set the width and height, we simply use the width and height attributes of an element. The value will be in DIP, and can also be set to the Auto value (which is default). The size is then determined based on the element contents, e.g. based off of the length of the text of the button title. You can also set a minimum or maximum size using the MinWidth, MinHeight, MaxWidth and MaxHeight attributes.
In the next lesson, Designing a calculator form in C# .NET WPF, we'll design a simple calculator form. You can download today's source code below as always.
Downloaded 11x (55.53 kB)
Application includes source codes in language C#
No one has commented yet - be the first!