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

Lesson 5 - Storing objects in CSV format in C# .NET, part 2

In the previous lesson, Storing objects in the CSV format in C#, we started coding an application for storing users in CSV files. In today's tutorial, we're going to finish and improve this application.

Loading users from the CSV file

Now that saving works, all that's left for us to do is to load the data back into the application. We'll read the file line by line, split each line using the Split() method, and then add an object with those values to the collection. We'll empty the collection before loading, so as to get rid of the users loaded from before (in case we extend the application in the future).

public void Load()
{
    users.Clear();
    // Opens the file for reading
    using (StreamReader sr = new StreamReader(file))
    {
        string s;
        // Reads it line by line
        while ((s = sr.ReadLine()) != null)
        {
            // splits the string line using semicolons
            string[] values = s.Split(';');
            string name = values[0];
            int age = int.Parse(values[1]);
            DateTime registered = DateTime.Parse(values[2]);
            // adds a new user with those values
            AddUser(name, age, registered);
        }
    }
}

The database class is now complete. Let's focus on the form part now.

The application presentation layer

First, we'll prepare new form controls (from the ToolBox). We'll add a Load button, then a userListBox ListBox with the Sorted property set to true. Then, we'll add a TextBox to enter a new user's name, a NumericUpDown for their age, and a DateTimePicker for their registration date. We'll set the shorter format to it. We'll also add some labels to the controls. We can group these controls using GroupBox. In another GroupBox, we'll add three labels for the user's details and name them nameLabel, ageLabel, and registeredLabel. We'll add 3 more labels to describe those as well. Finally, we'll add a button for adding a new user. We can make the application more user-friendly by adding a PictureBox with an icon. If this was all too much information for you, don't worry, here's a picture of the final form to help you get situated:

CSV user database form in C# .NET - Files and I/O in C# .NET

In a real application, adding users would probably be done in an entirely separate dialog. However, a single form is just fine for our purposes.

Let's remove the test users creation part from the Save button handler. Next, we'll add saving in a try-catch block. We already know that the finally keyword (the using block in our database) doesn't actually catch exceptions, which is what we want. Therefore, we'll react to them in the presentation layer (in the form), where we're supposed to. Error notifications, i.e. communicating with the user, would be done incorrectly if placed in the Database class. We'll pull up a MessageBox if we catch an exception. With all of that in mind, the button's handling method will look like this:

try
{
    database.Save();
}
catch
{
    MessageBox.Show("Unable to save the database, check the file's access privileges.",
        "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

We'll click a handler for the Load button in a similar manner, i.e. we'll load objects into the ListBox as well once they've loaded from the database. We'll clear the ListBox to avoid mixing the loaded users with the previous contents. In real applications, the loading would probably be performed automatically when the application starts. However, we'll leave that to the buttons for the better control. The Load button method now looks as follows:

try
{
    database.Load();
    userListBox.Items.Clear();
    userListBox.Items.AddRange(database.ReturnAll());
}
catch
{
    MessageBox.Show("Unable to load the database. The file might not exist.",
        "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Now let's handle clicking events for the userListBox, which will display the user details to the labels that we've prepared:

if (userListBox.SelectedItem != null)
{
    User u = (User)userListBox.SelectedItem;
    nameLabel.Text = u.Name;
    ageLabel.Text = u.Age.ToString();
    registeredLabel.Text = u.Registered.ToShortDateString();
}

We added a condition in case no user is selected (the listBox would be empty). The type casting of the selected item to the User data type is also worth mentioning. Since ListBox isn't a generic collection, C# has no idea what to do about the item types. Feel free to test it all out to make sure that it's all working properly.

There is one last button without a handler method and that's the one used to add new users. We'll click it and simply add a user. However, we'll have to add the item to both the ListBox and the database. In more complex applications, we'd use data binding, but we won't so as to keep things simple (see the Windows forms application course if you're interested in more information about it).

private void addButton_Click(object sender, EventArgs e)
{
    string name = fullNameTextBox.Text;
    int age = Convert.ToInt32(ageNumericUpDown.Value);
    DateTime registered = registeredDateTimePicker.Value;
    database.AddUser(name, age, registered);
    userListBox.Items.Add(new User(name, age, registered));
}

Let's try to add a new user:

A form for adding a new users in C# .NET to a CSV file - Files and I/O in C# .NET

We could implement removing users in a very similar fashion, but I'll leave this up to you. The last thing that's left for us to do is to sanitize the file path that leads to the AppData folder (not the application's folder). We already know how to do it thanks to the Introduction to working with folders lesson. We could also clear the labels' text at the application start. We'll do it all in the form's constructor (don't forget to add using System.IO;).

public Form1()
{
    InitializeComponent();
    // clears the user detail labels
    nameLabel.Text = "";
    ageLabel.Text = "";
    registeredLabel.Text = "";
    // creates an application folder in AppData
    string path = "";
    try
    {
        path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "UserDatabase");
        if (!Directory.Exists(path))
            Directory.CreateDirectory(path);
    }
    catch
    {
         MessageBox.Show("Unable to create folder " + path + ", check your user privileges.",
           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    // creates a database
    database = new Database(Path.Combine(path, "users.csv"));
}

That's it! :)

Our application is almost done. Let's think for a bit about what would happen if someone wrote a semicolon in their name. As you may have guessed, the application would break. That's why we'll remove semicolons from the name in the Save() method. If we needed to store semicolons in our application (which isn't a very common thing), we could come up with another separator. If we wanted things to be perfect, we'd add the value with the semicolon in quotes. However, the Split() method will no longer suffice for parsing. If you're interested in parsing CSVs like this, take a look at the Microsoft.Visu­alBasic.FileI­O.TextFieldPar­ser class. Of course, we could also solve this problem by using a different file format. In this case, we'll simply remove semicolons. More accurately, we'll replace them with spaces by changing a single line in the Save() method:

string[] values = { u.Name.Replace(';',' '), u.Age.ToString(), u.Registered.ToShortDateString() };

We're now done. If you had any problems, the finished project is attached below, as always. In the next lesson, Introduction to XML and writing via the SAX approach, we'll introduce the XML format.


 

Download

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

Downloaded 709x (91.19 kB)

 

Previous article
Storing objects in the CSV format in C#
All articles in this section
Files and I/O in C# .NET
Skip article
(not recommended)
Introduction to XML and writing via the SAX approach
Article has been written for you by David Capka Hartinger
Avatar
User rating:
1 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