Lesson 4 - Designing a calculator form in C# .NET WPF
In the previous lesson, Positioning in C# .NET WPF, we learned all about positioning controls on a Window in C# .NET. In today's lesson, we're going to create our first real application, a simple calculator.
Lots of applications start out as designs, i.e. forms, and functionality is added along the way. Here's what our application will look like:
Now, let's get started! Create a new project named Calculator and set the window title to "Calculator". Then, add a new attribute to the window:
This will ensure that the window will appear in the center of the screen when the application starts.
There are several ways to achieve the desired results in appearance. What we're going to to do, is build the entire form upon a Grid control.
Up until now, we've treated Grids like panels, onto which we can insert controls. However, as the name suggests, it is more of a table. The Grid starts out with only one cell, one row, and one column, by default.
Let's move to the graphic designer and click on the middle of the window. This selects its inner parts which, in most cases, is the Grid. Every new window contains a Grid by default, without it, it would be very difficult to add multiple elements to a window. When we select the Grid, "rails" appear over the top and left edges. We can select a point there using the mouse and split it up into rows or columns (at the position in which you clicked). Now that that's been said, create a table of 2 rows and 5 columns. We'll add form controls to the table cells later on.
Looking at the Grid's XAML code, we see that two new elements have appeared:
ColumnDefinitions. These define the
number of rows and columns that are to be generated by the graphic designer. The
code is chock full of absolute sizes by default, which you should now know is an
inefficient thing. Edit the XAML code so looks like this:
<Grid Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="50"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="50"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="30"/> </Grid.RowDefinitions> </Grid>
We have set the Margin of the Grid to 10 DIP. What this does is keep the controls on the grid from being too close to the window edges.
In the number of columns and their widths specified in the column definition section (which is pretty self-explanatory). Take another look at the finished calculator form. There, you will see two fields for entering numbers and one for displaying the result. For large numbers, we would need to stretch the form to add more space. What the Grid does, is respond to that need and stretch all three of the cells and their sub-elements to "make" more space. However, there will be cases where we don't want the grid to resize the cells. For example, the cells containing the arithmetic operations ComboBox and the "equals" sign should not be resized because it is unnecessary and confusing to do so. Therefore, these two columns have fixed size of 50 DIP. The others are set to "*" which fills the remaining space within them equally.
If you need certain columns of cells to be wider/narrower than the others, set them using the asterisk value in the direction of "growth/shrinkage" you want the value to follow. For example, a column that is to be twice the size of the others would be set to "2*". Whereas, a column that is to be half the size of the others would have to be set to "*0.5".
Row definitions are done in a similar fashion. Here, the second row is exactly 30 DIP high, and the first row is set to fill the rest of the window.
Technically, we could set everything from the Graphic designer. However, it would be a bit harder to achieve the same results and would get progressively more, and more difficult
Now that that's done, let's add several more elements in the Grid definition.
We'll start out by adding a button:
<Button Content="Calculate" Width="80" VerticalAlignment="Center" Grid.Row="1" Grid.Column="2"/>
Here, we have set the button's width to 80 DIP, its vertical alignment to center, and set the text label using the Content attribute. We don't need to set the horizontal alignment once a fixed width has been specified, the button will be centered horizontally.
The attributes that matter most to us in this case, are the Grid.Row and the Grid.Column attributes. What they do is indicate precisely where we want the control to be inserted (which cell the control should be inserted into). As always, the index starts from zero (meaning that the "first row" is actually the "0th" row).
A TextBox is a field used for text input. Our application needs two of them, so we will need to add the following code to the grid:
<TextBox VerticalAlignment="Center" Grid.Row="0" Grid.Column="0" Margin="0,0,10,0" Text="0" /> <TextBox VerticalAlignment="Center" Grid.Row="0" Grid.Column="2" Margin="0,0,10,0" Text="0" />
Keep in mind that we inserted the TextBoxes into the first Grid row, whose height stretches along with the form. In order to keep things looking good, we'll have to center them vertically. We'll set the right margins to 10 DIP and the texts to 0 (which is the default input value of almost all calculators). Also, don't forget to enter the grid cell's coordinates correctly.
Just so you know, in order to enter multi-line text you would have to add these two attributes to the TextBox (we won't be using it on our calculator):
A ComboBox is a drop-down list of several items. In this application, we'll use it to choose from a set of predefined operations, i.e. +, -, *, /.
Our combobox will be defined as follows:
<ComboBox VerticalAlignment="Center" Grid.Row="0" Grid.Column="1" Margin="0,0,10,0" SelectedIndex="0"> <ComboBoxItem Content="+"/> <ComboBoxItem Content="-"/> <ComboBoxItem Content="*"/> <ComboBoxItem Content="/"/> </ComboBox>
The SelectedIndex is the index of all of the selected items, which in our case is the first. Individual items are nested in the ComboBox as ComboBoxItem elements. We use the content attribute to set their text label. As a matter of fact, you can insert almost anything in there, be it images, colors, or whatever it is you need.
The last couple of things we are going to add to our calculator today are TextBlocks (which we are already familiar with):
<TextBlock Grid.Row="0" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center">=</TextBlock> <TextBlock Grid.Row="0" Grid.Column="4" VerticalAlignment="Center" HorizontalAlignment="Center">0</TextBlock>
The first TextBlock is the "equals" sign between the second number and the result, the second one holds the result.
Done! Don't forget to resize it to make sure the relative positioning parts function properly! All of the controls should adapt beautifully regardless of the window size.
If you want, you can change the window icon by dragging an .ico file and dropping it in the Solution Explorer window. Then, all you would have to do is add the Icon window attribute and set its value to the file's name. Another improvement you can add is to set the minimum width and height of the window so the that the window won't be able to shrink too much.
<Window x:Class="Calculator.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:Calculator" mc:Ignorable="d" Title="Calculator" Height="134" Width="388" MinWidth="388" MinHeight="134" WindowStartupLocation="CenterScreen" Icon="calculator.ico">
In the next lesson, Code-Behind in C# .NET WPF and finishing the calculator, we'll program the logical part of the application and we'll also go a bit further into detail about how WPF internally.
Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.
DownloadBy downloading the following file, you agree to the license terms
Downloaded 53x (102 kB)
Application includes source codes in language C#