Lesson 6 - Birthday reminder in C# .NET WPF - Designing windows

C# .NET WPF Birthday reminder in C# .NET WPF - Designing windows

In the previous lesson, Code-Behind in C# .NET WPF and finishing the calculator, we finished making a simple calculator application in C# .NET. In the next couple of lessons, we're going to create an application I deem to be at a more intermediate level. It will remind the user of his/her friends' birthdays. The end result will look like this:

Birthday reminder in C# .NET WPF

The application is made up of two forms, which we will use to work with dates and store data into files. Also, we are going to incorporate the Model-ViewModel architecture, exceptions, and bindings. This lesson will go over a lot of new information, but don't worry, we'll go step by step. I believe that practical, relatively simple examples are the best way to go when learning to code. I'm sure you'll make it through unscathed.

Form design

We'll start with the design, as always. Create a new WPF project and name it BirthdayReminder.

The main form

Set the window title, its starting position (on the screen), and an icon.

Layout

There are several ways to achieve the desired form layout. One way would be to split the Grid as follows:

Window grid in C# .NET WPF

The grid would have 4 rows and 2 columns. Rows heights are 20, 30, * and 30 DIP. The second to last one stretches along with the window. The left column has a width of *, the right one has a fixed width of 200 DIP. The overall Margin is set to 10 DIP. Once you have set all of the above, your Grid code will look like this:

<Grid Margin="10">
        <Grid.RowDefinitions>
                <RowDefinition Height="20"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
</Grid>
Upper TextBlocks

In the first two rows of the Grid, we set up a couple of TextBlocks with information about today's date and the nearest upcoming birthday. The text consists of several parts. We could potentially use a single TextBlock in each row and concatenate its text value, but to keep it simple, we'll add several TextBlocks next to each other.

StackPanel

When laying controls next to each other, vertically or horizontally, we use StackPanels. A StackPanel is used to store controls, kind of like the Grid. Add a StackPanel into each row in the grid. We not only want the StackPanel to be in the first column but in the entire row. Which is why we add the ColumnSpan attribute with a value of 2 (which stretches it over two columns). It works sort of like colspan in HTML or merging table cells in Excel. Also, there is such a thing as a RowSpan which stretches the element over several rows. We'll set the Orientation attribute of the StackPanels to Horizontal (the default value is Vertical). As well as add individual TextBlocks straight into them (leave the data display TextBlocks empty).

<StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Orientation="Horizontal">
        <TextBlock Text="Today is "/>
        <TextBlock Text="" />
</StackPanel>

<StackPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal">
        <TextBlock Text="The nearest birthday has "/>
        <TextBlock Text=""/>
        <TextBlock Text=" in "/>
        <TextBlock Text=""/>
        <TextBlock Text=" days."/>
</StackPanel>
Bottom buttons

Next, add two buttons to the last window row in the exact same way. Once again, they will be in a StackPanel and stretch over two columns because we want them next to each other. The StackPanel will be centered. We will have to assign names to the buttons, in this case, because we will use them in the code-behind, later on. Also, you will have to set the left button's right Margin to 10 in order to keep them from being too close together.

<StackPanel Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center">
        <Button Width="100" Margin="0,0,10,0" Name="addButton" Content="Add"/>
        <Button Width="100" Name="removeButton" Content="Remove"/>
</StackPanel>

The form should now look like this:

StackPanels in C# .NET WPF

Go ahead and run the application. Make sure to resize the window to make sure that everything is responsive.

ListBox

All of the stored people instances will appear in a ListBox control. As the name of the control suggests, it is a visual representation of an item list. As a matter of fact, ListBoxes are an upgraded version of the ComboBox control. Therefore, we work with them in the same way. In our case, we won't need to define the items in XAML. However, we will load them later in the logical layer of the application. Add a ListBox to the first column's third row, Name it personsListBox and set its bottom Margin to 10 DIP.

<ListBox Name="personListBox" Grid.Column="0" Grid.Row="2" Margin="0, 0, 0, 10"/>
Calendar

The last couple of things we will add to this form is a calendar and a few TextBlocks above it. We could either create another Grid in its designated cell or use a StackPanel (which we could use to line up our controls horizontally/ver­tically). We'll go with the StackPanel because it is a bit more flexible. Start by setting it's Left Margin to 10 DIP. Then, add 2 TextBlocks side by side to each row, which will be in separate StackPanels. Calendars are declared as conveniently pre-made Calendar controls, which are mainly used to choose a date and display it (which is basically what we need it for).

<StackPanel Grid.Column="1" Grid.Row="2" Margin="10, 0, 0, 0">
        <StackPanel Orientation="Horizontal">
                <TextBlock Text="Birthday: "/>
                <TextBlock Text="" />
        </StackPanel>
        <StackPanel Orientation="Horizontal">
                <TextBlock Text="Age: "/>
                <TextBlock Text="" />
        </StackPanel>
        <Calendar Name="birthdayCalendar" />
</StackPanel>

The main form is now complete.

Add-person dialog

Add a new window to the project, right-click on the project in the Solution Explorer -> Add -> Window, and name it PersonWindow. Again, set the title, the starting position, and the icon.

Let's take another look at the final result (the new window you just created will be for the form on the right):

Birthday reminder in C# .NET WPF
Layout

Now, split the Grid into 4 rows and 2 columns. Row heights will be as follows: 4*, 30, 30, *. The first and the last row stretch along with the window. Also, notice how the first one occupies 4 times more space than the last one. Both columns will have a width of *, which is the default value, so just leave that part as is. Next, set the Margin around the whole Grid to 10. Once you have done all of this, the form will look like the following:

Window Grid in C# .NET WPF

And the code is:

<Grid Margin="10">
        <Grid.RowDefinitions>
                <RowDefinition Height="4*"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
        </Grid.ColumnDefinitions>
</Grid>
Image

Let's add an image, as well, so you could get some more experience working with them. There are lots of icons available for download at http://www.iconfinder.com. Make sure you read what kind of license the icon is under before you use it commercially. Once you have downloaded an image, add it to the form using an Image control. Before you do so, you will have to add it to the project in the same way you did with the icon (dragging it to the Solution Explorer). Once you have added the image to your project, set the name of the file to the Source attribute of an Image control.

When you have a project in which you plan to use lots of images, make sure you create a folder exclusively for them. Images stretch to fill the parent control by default, which is not something we want. All you have to do to make it keep its original proportions is set the Stretch attribute in the Image control to "None". Last, of all, add the image to the entire Grid row using ColumnSpan.

<Image Source="person_add.png" Stretch="None" Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="0"/>
Label

We also need to add controls for entering names and birthdays in the next two rows (on the second column). Start by placing a label for each control into the first column. TextBlocks wouldn't don't suit our needs in this case, which is why we will use labels. Labels text blocks that are bound to a particular control. They also allow us to set keyboard shortcuts by placing an underscore before a letter in its text. Then when you press ALT + the letter you wrote, the control to which the label belongs will gain focus. To write an actual underscore, one that doesn't set keyboard shortcuts, just write two of them.

A TextBox will do for entering names. As for the birthday, we'll use a DatePicker control. Let's take a peek at how that would look:

<Label Content="_Name" Grid.Column="0" Grid.Row="1" Target="{Binding ElementName=nameTextBox}"/>
<Label Content="_Date of birth" Grid.Column="0" Grid.Row="2" Target="{Binding ElementName=birthdayDatePicker}"/>
<TextBox Grid.Column="1" Grid.Row="1" Name="nameTextBox" Margin="0,0,0,5"/>
<DatePicker Grid.Column="1" Grid.Row="2" Name="birthdayDatePicker" Margin="0,0,0,5"/>

We can see that the connection between the Label and the control is done by the Target attribute. Also, notice the expression in the curly brackets that starts with the word "Binding". Which literally binds things to one another, in this case, a Label to a control of a given name. We'll run into binding pretty often, so make sure you remember what it does! The rest of the code is nothing new. Another thing we still have to add is to make the form visible at runtime. We will get to that in the next lesson as well as make it so when you press ALT + J, the focus will be set to a name field. Whereas, ALT + D will set the focus on the DatePicker.

Let's finish the dialog off by adding in the confirmation button, which will appear in the middle of the last row.

<Button Name="okButton" Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Bottom" Width="100" Content="OK"/>

We can set what the "default" and "cancel" keys do in every WPF window. The enter key is the default key and triggers the OK button when pressed, whereas the escape key triggers the cancel button. Now that that's been said, let's add the IsDefault attribute to the button:

IsDefault="True"

If we wanted to close the dialogue by pressing Escape, all we would have to do is add a Close button and set the IsCancel attribute to True to it.

Well, that's it for today! I think you've done plenty of form designing in XAML for one day. Hopefully, you learned some new useful techniques as well. In the next lesson, Birthday reminder in C# .NET WPF - Logic layer, we'll start working on the logical layer of the application as well as the C# code. If needed, the form we designed today is available for download below.


 

Download

Downloaded 48x (179.22 kB)
Application includes source codes in language C#

 

 

Article has been written for you by David Capka
Avatar
Do you like this article?
2 votes
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn College The author learned IT at the Unicorn College - a prestigious college providing education on IT and economics.
Activities (8)

 

 

Comments

Avatar
Filip Dostál
Member
Avatar
Filip Dostál:5/20/2017 4:34

Ahoj Davide, mám otázku. Šel by vytvořit Birthday Reminder, který by předem upozornil na datum narozenin? Databáze by byla vytvořená v Micosoft Access. Mám již vytvořenou databázi, kterou mám připojenou v datagridu, ale teď nevím, jak vytvořit upozornění. Můžeš mi poradit.

 
Reply 5/20/2017 4:34
Avatar
David Capka
ICT.social team
Avatar
Replies to Filip Dostál
David Capka:5/22/2017 4:07

Please, use the English language when posting at ICT.social. About your question, you need to order items in your data source by birth date and set a timer (look for DispatcherTimer) which will check whether there is an upcoming birthday to remind. Your reminder can use the tray notification, look for NotifyIcon.

Edited 5/22/2017 4:08
Reply 5/22/2017 4:07
You can walk through a storm and feel the wind but you know you are not the wind.
Avatar
pangras
Member
Avatar
pangras:8/19/2017 5:03

why the person window does not work properly5

 
Reply 8/19/2017 5:03
Avatar
David Capka
ICT.social team
Avatar
Replies to pangras
David Capka:8/20/2017 15:37

If anything doesn't work in your project, download the sample solution below the article.

Edited 8/20/2017 15:37
Reply 8/20/2017 15:37
You can walk through a storm and feel the wind but you know you are not the wind.
To maintain the quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it's free.

4 messages from 4 displayed.