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.
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.
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.
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:
private void goButton_Click(object sender, EventArgs e)
{
}
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.
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:
private void dgvResult_SelectionChanged(object sender, EventArgs e)
{
}
which is wired up in the designer.cs file like so:
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.
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:
private void CountFiles()
{
List<string> filenames = new List<string>();
int total = 0;
string[] extensions = txtExts.Text.Split(" ".ToCharArray());
foreach (string ext in extensions)
{
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
.
dgvResult.Rows.Clear();
foreach (string filename in filenames)
{
int count = CountLinesInFile(filename);
total += count;
dgvResult.Rows.Add(
filename.Substring(Directory.GetCurrentDirectory().Length+1),
count.ToString());
}
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:
private void CountSelection()
{
int selected = 0;
int total = 0;
foreach (DataGridViewRow row in dgvResult.Rows)
{
try
{
if (row.Selected &&
row.Cells[0].Value.ToString() != "Total:")
{
selected++;
total += int.Parse(row.Cells[1].Value.ToString());
}
}
catch { }
}
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.