Get up to 80 % extra points for free! More info:

Lesson 4 - Birthday Reminder - Logic Layer

In the previous lesson, Birthday Reminder - Designing Forms, we designed all the forms for our application. In this tutorial, we're going to design the logical layer, that is, classes containing the application logic.

Person

We'll certainly work with people in our app, so let's create a class for them. Be sure to put the public modifier before the class name.

Properties

The person will have 2 properties: name and birthday. Name will be string, Birthday will be of the DateTime type. We're going to set these properties using a parametric constructor.

public class Person
{
    public string Name { get; set; }
    public DateTime Birthday { get; set; }

    public Person(string name, DateTime birthday)
    {
        Name = name;
        Birthday = birthday;
    }

}

Methods

In addition to the constructor, the class will have CalculateAge() and RemainingDays() methods.

CalculateAge()

The method calculates and returns the person's current age in whole years. Unfortunately, this calculation isn't just about subtracting two dates, since TimeSpan can't determine the number of years, only the number of days. To calculate the age, we'll follow these steps:

  1. We'll get the current date (without time) using DateTime.Today.
  2. We'll calculate the age as the difference of the current date's and the birthday's years. You probably know that such age isn't accurate. If we were born on 2/1/1990 and today is 1/1/2010, we aren't 20 years old, but only 19. For this reason, we'll make a correction.
  3. If the current date is before the date of birth plus the years we've calculated, the above case has occurred and we have to reduce the age by one year.
  4. We'll return the final age we calculated.

The method's code looks as follows.

public int CalculateAge()
{
    DateTime today = DateTime.Today;
    int age = today.Year - Birthday.Year;
    if (today < Birthday.AddYears(age))
        age--;
    return age;
}

RemainingDays()

This method returns how many days remain until the person's birthday. Here's how to find out:

  1. We'll get the current date (without time).
  2. We'll get the next birthday by adding age + 1 to the date of birth.
  3. We'll subtract the dates and return the total day difference. Since the difference is of the double type, we have to convert it to the int type.
public int RemainingDays()
{
    DateTime today = DateTime.Today;
    DateTime nextBirthday = Birthday.AddYears(CalculateAge() + 1);

    TimeSpan difference = nextBirthday - DateTime.Today;

    return Convert.ToInt32(different.TotalDays);
}

ToString()

Since we're going to list the people, we'll override the ToString() method to return the person's name:

public override string ToString()
{
    return Name;
}

Person Manager

The next logical component of the application will be a person manager. The class will take care of all the people, will be able to add them, remove them, and save their list into a file and reload it. And finally, it'll be able to find the person with the nearest birthday among all the people.

Create a PersonManager class in the project and make it public.

Properties and Attributes

The only public property of the class will be a list of the people. The list will be of the BindingList type. We haven't met this collection type yet. It's a smarter List that can trigger a change event when its content changes. This mechanism automatically refreshes all the controls in a form that have this BindingList set as the data source. You can imagine that refreshing dozens of controls in a form manually after every change can be very confusing. Once we add a new person in our app, it'll be visible in the people list immediately without us having to refresh it from the code, it'll refresh itself. We'll initialize the BindingList in the constructor.

If we wanted to implement people editing, the Person class would need to implement the INotifyPropertyChanged interface. Any change (changing the name for example) would then be automatically reflected in all controls of all forms where this person appears. However, we won't be doing this here to keep things simple.

So far, the class looks like this:

public class PersonManager
{
    public BindingList<Person> People { get; set; }

    public PersonManager()
    {
        People = new BindingList<Person>();
    }

}

Methods

In addition to adding and removing, the class will also be able to find the person with the nearest birthday. We'll discuss saving and loading people to/from a file later.

Add()

This method adds a new person to the BindingList. Since we use a form to add the person, it'll be useful if the method took the person's properties as parameters and created a new instance based on those. From the date of birth we'll only save the date part, without the time.

Before adding the person, we'll make sure the name isn't too short and the date entered isn't in future. If any of these situations occur, we'll throw an exception. Exceptions are the right way to handle errors in object-oriented applications.

Exceptions are explained in more detail in Working with Files in C# .NET. If you haven't met those yet, you only need to know that we throw an exception using the throw keyword, followed by the exception instance. There are several types of exceptions, and we can also create our own. In our case, we can use ArgumentException. We enter the error message as a parameter of the exception constructor. Once the exception is thrown, the method no longer continues. We're going to handle the error later when we'll call the method from the form.

public void Add(string name, DateTime birthday)
{
    if (name.Length < 3)
        throw new ArgumentException("Name is too short");
    if (birthday.Date > DateTime.Today)
        throw new ArgumentException("Birthday must not be in future");
    Person person = new Person(name, birthday.Date);
    People.Add(person);
}

Remove()

This method removes a person from the BindingList. Since we always want to remove an already completed person, this method takes the person instance as a parameter.

public void Remove(Person person)
{
    People.Remove(person);
}

FindNearest()

This method finds and returns the person with the nearest birthday. To find the person in the collection, we'll use the LINQ OrderBy() method to order people by how many days remain until their birthday. We'll store the result in a collection which type we're not going to specify and use the var keyword instead, as is customary with LINQ. Then we'll return the first person. We should only call the method if there are people in the collection. Although it should be clear from the code what the method does, you can, of course, look at the tutorials in the Collections and LINQ course, where LINQ is described in more detail.

public Person FindNearest()
{
    var sortedPeople = People.OrderBy(p => p.RemainingDays());
    return sortedPeople.First();
}

We'll continue in the next lesson, Birthday Reminder - Wiring the Presentation and Logic Layers, to get the app up and running. The current source code is available to download below.


 

Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.

Download

By downloading the following file, you agree to the license terms

Downloaded 86x (717.23 kB)
Application includes source codes in language C#

 

Previous article
Birthday Reminder - Designing Forms
All articles in this section
Form Applications in C# .NET Windows Forms
Skip article
(not recommended)
Birthday Reminder - Wiring the Presentation and Logic Layers
Article has been written for you by David Capka Hartinger
Avatar
User rating:
5 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 university David learned IT at the Unicorn University - a prestigious college providing education on IT and economics.
Activities