Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Basic File IO and the DataGridView

3.20/5 (6 votes)
26 Jul 2008CPOL4 min read 1   775  
Create a versatile line reading application using the .NET StreamReader and the DataGridView.

Sample Image - LineCounter.png

Introduction

If you have ever wanted to know how quickly you write code, you have probably counted lines. As programs get more involved and work is shared among a team, it is difficult to know how many lines are "owned" by you.

Lines of code may not be the best way to measure performance (I am imagining a classroom full of monkeys striking Enter, Enter, Enter... ). But sometimes, it is satisfying to say, "Look what was done!"

This articles explores basic file IO, how to manually store results in a DataGridView, and basic event handling.

Wiring up the GUI

The GUI has just a few components. A TextBox provides a place where we can enter the file extensions we are interested in counting. A DataGridView provides a place to show results. A CheckBox provides us some options, and a StatusStrip helps us summarize the results to the user.

Use the Anchor property to adjust how each Control "clings" to the walls of the Form. This allows us to resize the window to get a better view if we have long filenames or a large number of results. Anchoring is one of the convenient layout tools built in to the environment.

Sample image

Now, we will wire up the columns in the DataGridView control. The form editor makes this a breeze. Highlight the DataGridView and select the Columns property.

Sample image

We now have a dialog that can be used to generate our columns. Clicking on the Add button opens an additional dialog that can be used to create columns. Choose a name and header text, and the column type of DataGridViewTextBoxColumn. Other interesting column properties include FillWeight, which affects how much priority the column receives during layout.

Sample image

The next step to giving the GUI functionality is to add event handlers. For example, when we click on the Go button, we want the application to find files that match our search criteria, open them, and count lines.

We can use the form editor to add this handler easily. Just double-click on the Go button, and the event handler is added for us, like so:

C#
private void goButton_Click(object sender, EventArgs e)
{
  // TODO: Count files here...
}

Also, the function is registered with the event delegate in the designer.cs file. This is what tells the runtime that we want to run the goButton_Click method when the goButton.Click event is fired.

C#
this.goButton.Click += new System.EventHandler(this.goButton_Click);

Because there may be files found by our program that we want to ignore, we will wire up the DataGridView to gather information about selected files only. We can then pick and choose which results we want to tally up for our final line count.

Using the form editor, we set the MultiSelect property to True and the SelectionMode property to FullRowSelect. All that's left is adding an event handler to respond to changes in the selection. Find the SelectionChanged property in the form editor, and double-click to generate the following method:

C#
private void dgvResult_SelectionChanged(object sender, EventArgs e)
{
  // TODO: Count the selection here.
}

which is wired up in the designer.cs file like so:

C#
this.dgvResult.SelectionChanged += 
         new System.EventHandler(this.dgvResult_SelectionChanged);

A lot of changes can happen by playing with the properties in the form editor, but let's move on to the meat of the project, cranking out our own lines of code.

Using a StreamReader to count the lines in a file

Reading a file from the system is very easy in C#. The key objects involved are File and StreamReader. The static method File.OpenText opens a file specified by a local or fully-qualified path name, and generates a StreamReader object to digest the file contents. StreamReader is built with the ReadLine method; perfect for our task.

C#
private int CountLinesInFile(string filename)
{
    StreamReader sr = File.OpenText(filename);
    int count = 0;
    while (sr.ReadLine() != null)
      count++;
    sr.Close();
    return count;
}

Finding Files in a Directory

Our next task is to determine which files we should open. We will make use of the System.Collections.Generic.List<> class to contain our filenames. The following code snippet demonstrates how we collect all the filenames that match the requested extensions:

C#
private void CountFiles()
{
    // Repository for discovered filenames 
    List<string> filenames = new List<string>();

    // Running linecount total
    int total = 0;

    // The Split method is a quick and dirty way to parse a string.
    string[] extensions = txtExts.Text.Split(" ".ToCharArray());

    foreach (string ext in extensions)
    {
      // The third parameter of this overload allows us to 
      // automatically inspect subdirectories. Default is 
      // SearchOption.TopDirectoryOnly, and the argument 
      // could have been omitted, but is included here for
      // information's sake.
      filenames.AddRange(
        chkSubDir.Checked ?
        Directory.GetFiles(
            Directory.GetCurrentDirectory(),
            "*." + ext,
            SearchOption.AllDirectories) :
        Directory.GetFiles(
            Directory.GetCurrentDirectory(),
            "*." + ext,
            SearchOption.TopDirectoryOnly));
    }

    // ...

Our next task is to open each file, count the lines, and add the results to the DataGridView. We will use the DataGridView.Rows.Add(object[] params) method to add each new row. With this method, each object should correspond, in order, to the columns of the DataGridView.

C#
    // ...

    // Wipe out any previous results
    dgvResult.Rows.Clear();

    // No that we have all the filenames, 
    // open the files to count their lines.
    foreach (string filename in filenames)
    {
      int count = CountLinesInFile(filename);
      total += count;

      // This line adds a new row to the DataGridView.
      // We choose the string.Substring method to display
      // only the relative path of the file
      dgvResult.Rows.Add(
        filename.Substring(Directory.GetCurrentDirectory().Length+1),
        count.ToString());
    }

    // Add the total to the bottom
    dgvResult.Rows.Add(
       new object[] { "Total:", total.ToString() });
}

Call this method from the goButton_Clicked event handler, and we have a line counter!

Using MultiSelect with the DataGridView

To wrap things up, we will add functionality to ignore some of the results, if we wish, in our total. The following code snippet counts the results in the selected rows, and writes the results to the StatusStrip below:

C#
private void CountSelection()
{
    int selected = 0;
    int total = 0;
    foreach (DataGridViewRow row in dgvResult.Rows)
    {
        try
        {
            // Ignore rows that are either not selected 
            // or are the total row. Because some "filler"
            // rows exist, use the catch block to effectively
            // ignore the invalid data in those rows.
            if (row.Selected &&
                row.Cells[0].Value.ToString() != "Total:")
            {
              selected++;
              total += int.Parse(row.Cells[1].Value.ToString());
            }
        }
        catch { }
    }

    // Update the status label with the results
    lblFileCt.Text = selected.ToString() + " files selected";
    lblLineCt.Text = total == 0 ? "No lines" : total.ToString() + " lines";
}

Conclusion

This article just scratches the surface of file IO and data controls like the DataGridView. I hope you found this article useful. This article is updated and maintained on the author's website at http://www.notesoncode.com/articles/2007/06/11/BasicFileIOAndTheDataGridView.aspx. Your feedback is welcome. Thank you for reading.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)