Before you do anything, you need to download the .NET framework, as well as the .NET SDK, both available from HERE
When you’ve done that, of course you will need a development environment. I recommend #develop (http://www.icsharpcode.com). You can also use the Borland C#Builder, but it isn’t nearly as good, in my eyes atleast.
I try not to assume anything in this tutorial, but knowing atleast some basics will help, but I will try to explain everything to the best extent I can. I do assume SOME very basic programming experience.
What you will learn:
-Small GUI coding skills
-How to utilize recursive functions
There is probably more you will learn, I’m just paraphrasing the key things I will be addressing.
To begin, open your IDE (prefferably #develop), and start a new Combine project, and name it whatever you like (it will be a file searching application, so name it something logical). You should get something like this up:
This is an empty WinForm, the base of your application. Below it you can see Source (or Code in Borland C#Builder) and Design. First of all we need to slap on some WinForm components, or else the whole thing would be useless.
Designing the application is highly individual, and I don’t want to give you guidelines on how you should make your application look. So I will just give you the components you need, and let you place them where you want. You should however resize your application to be considerably bigger than what it is now, or else things will get really cramped.
You will need:
| -One single-line text box for user input, the kind looking like this | ||
| -One ComboBox for listing root directories, looking like this: | ||
| -Two Checkboxes, looking like this: | ||
| -One button which will be the “Search” button, looking like this: | ||
| -One ListBox, sized to your own desire. | ||
| -One multiline standard or rich edit text box. |
When you have inserted all these, and organized them to look good, or functional, or whatever you want your application to look like, then you’re done with that bit. Now, we have that search button. If you don’t know how to change the look of your visual components, here’s how:
Go to the Design area of your winform. To your right, there should be a column of properties. Look for the “Text” property, and change this to whatever you want with each visual component. You’d want your Search button to display “Search” for example…
Also, if you want to, you can change the name of your components. It’s good to do this, or atleast have a look at what the IDE set their names to be, since you will need to know what they are to manipulate them.
When you’ve done this, we have as said earlier a search button. Currently, if you compile and run your application, it will not do anything. So we need to make it do something. In the Design part, double click the button. This should bring you to the Source area, and the IDE will have added something called an Event Handler. This means that what you put here, will be executed when the button is pressed.
Of course the key thing we want it to do is execute a searching function, but first we need to do something else, which I like to call foolproofing. We need to prevent ID 10 T users from doing stupid things, like pressing the button more than once. So, when we press the button, we should make it do a number of things before even thinking about the searching:
-Disable the button
-Disable the search input area
-Disable the directory listing
-Disable the checkboxes
*Change button text
The Change button text is not reall necessary, but looks cool
First, to disable the button. I’m assuming here that the button’s name is simply “button”. Change this to make it fit the name of the name you have given the button, or the name the button was given by your IDE. The syntax for altering a property for any visual component is
button.Enabled = false;
Pretty logical wasn’t it? Now we need to do the same to the search input area, directory listing and the checkboxes:
searchInput.Enabled = false;
dirListing.Enabled = false;
checkBox1.Enabled = false;
checkBox2.Enabled = false;
Notice that you need to change the names of the components to match your own. To change the text for anything, you do
button.Text = “Searching…”
After you’ve done all this, it’s time to worry about the actualy functions that deal with the searching of directories for files matching the user input. First, we need to name our functions. We will have 2 functions here, one searching directories and printing out the filenames it finds that match, and one that will print out the first paragraph of text files found that match the search criteria. The latter was just added by me as a challenge to learn the language, so I’m thinking it could be useful for you as well.
For simplicity, the functions are dubbed DirSearch(string Directory) and TextSearch(string Directory, string SearchInput).
If I lost you there, let me explain. The text in the parenthesis are the variable arguments these functions will take. String is a type declaration for a multi-character variable, and after that comes the variable name. Note that you don’t have to use string declaration in other functions in other apps you make. Beyond that, the arguments should be pretty self-explanatory.
Now we have ALMOST everything covered, before we get cracking. No one ever said this would be done in a jiffy. In the Design area of your WinForm, your titlebar most likely says “This is my WinForm” or something of that sort, unless you changed it. Double click it, and you should have an event handler that is called MainFormLoad(object sender, EventArgs e), unless you also changed the name of your form, in which case it will be
This is for when you run the program. When the program is executed, whatever you put in here will be done. What you want done here is to clear the logical drive combobox before getting them, and then, get the logical drives. This is to a) make sure there is no useless drivel that you might have forgotten to remove during coding and b) get the logical drives for that specific computer, as the drive letters vary from computer to computer.
Stuff in a combobox is organized into “Items”, which makes it very easy to clear. To clear the whole thing, just do:
dirListing.Items.Clear();
And it will be empty. Now of course we want things added again. To do this, we use a foreach loop. This will be really the only loop used in this application.
“Foreach goes through a loop for each member of a collection of objects, putting one object into a specified variable until the collection has no more objects to go through. Each object will get hit once and only once unless the collection itself is altered during the loop, in which case it could go on infinitely.”
So everytime the loop goes, you will get 1 object, so naturally you will want to print this object each time the loop goes, or you will end up with just the one object. I will now give you the code to do it, and then I will analyze it for you.
foreach (string s in Directory.GetLogicalDrives())
{
dirListing.Items.Add(s);
}
cboDirectory.Text = “C:\\”;
foreach is of course the start of the loop. In the parenthesis you see the “string” type declaration for the variable “s”, note that you can change this variable to be whatever. “string drives” works equally well, etc.
in Directory.GetLogicalDrives() Should be pretty self-explanatory. It checks for an object in the Directory.GetLogicalDrives() method, which is the listing of all logical drives in the computer the application is run on, and puts an object in the string variable “s” and does so until there are no more objects to add. Within the brackets are the actions you want the programs to take FOREACH time that one object is added to this variable, namely add it to the Directory Listing ComboBox. You see it’s pretty logical. componentName.Items.Add(variable);
After the brackets, we want to change the default option to be C:\ because this is after all the drive letter most common as the root HDD directory on computers. Note the double-slash, for those familiar with PHP, that’s the escape-character. Naturally it is necessary when you want to pring the escape character itself :P
Now everything is set, and we can start making the functions itself.
void DirSearch(string sDir)
{
try
{
This is what the start of out application looks like. It declares a void function (meaning it doesn’t return a value) that takes ONE argument, and stores this argument as a string variable called sDir. The try is in case something bad happens, or a so-called exception is thrown. If you do not include an exception handler, and an exception is thrown, a nice, very red popup window will come up and tell the user an “Unhandled exception occured” and Windows will force-close the application. You can tell the application what to do when an exception happens by adding the catch (System.Exception instance_name) after the try. Then you can for instance have a messagebox come up with the Exception text describing what went wrong. Usually these will just be warnings of some sort. I will get back to this.
Now we want it to first of all go through every folder and respective subfolders on the loical drive we are searching and do something. But before we can do something, we have to get the folders in which to do anything. So we use another foreach loop:
foreach (string d in Directory.GetDirectories(sDir))
{
This foreach loop makes a string called “d” and goes over all folders and subfolders until there is none left to go over, each time storing a subfolder name in the string variable “d”. The sDir is the argument we will pass initially when we press the Search button (will get back to that when we’ve finished writing the actual functions) and this will initially be a root directory (C:\, D:\ or whatever drive letter the user has chosen). And then, within this foreach loop, we can now add another foreach loop to add files in the “Matching files” listBox:
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, searchInput.Text))
{
The Directory namespace is a member of the System.IO namespace, so for this to work, you will have to put using System.IO; at the beginning of your code. Usually when creating a WinForm the most essential namespaces will be included automatically, such as the root System namespace. So you can strictly speaking do the same without declaring the use of System.IO by just using IO.Directory.GetDirectories(args), but the less typing you have to do, the better right?
Now, the foreach loop we just added within our previous foreach loop is the GetFiles method in the Directory namespace. It takes 1 argument originally, which is “string path”. This means that if you do simply Directory.GetFiles(C:\), it will get all the files in that directory (not subfolders). However, this function is “overloadable”, so we can make it take 2 arguments, and thereby getting it to filter out the files we are looking for. In this case, we use the filter that the user put in the searchInput text box. Note that the user will have to use asterisks in this version if he wants to find files that are similar or close to his or her search criteria, but putting in “license.txt” without asterisks will work fine for showing files that match exactly. Putting in “*ense.txt” will show all license.txt files and other files that end with “ense.txt” etc.
Now that we have a loop that puts a filename matching the criteria into the variable string f, so now we have to print that variable for each time the loop runs. This will be done in the listBox, and as you might recall, everything in a listbox is organized into Items so it is really easy to add something:
listBoxName.Items.Add(variable);
So, our finished DirSearch method would look like this:
void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, txtFile.Text))
lstFilesFound.Items.Add(f);
DirSearch(d);
}
}
catch (System.Exception excpt)
{
MessageBox.Show(excpt.Message, “Warning”, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
}
}
You will see that I make the method call itself when it has printed all the items in one subdir, in order to make it do absolutely all subdirs, each time the first foreach sends a different directory name to the string variable “d”, which is sent as an argument to DirSearch(string path) and stored again as string variable sDir. Just keep reading that until it makes sense, you’ll get it.
You will also see the “catch” thing at the end. This is what prevents a nice red popup saying an unhandled exception occurred. It should be pretty self-explanatory, but just in case it isn’t, here’s what it does: It instantiates System.Exception into an object named excpt. You have to do this, since System.Exception is a non-static namespace. Then it pops up a MessageBox (shows it), with the message of what went wrong (excpt.Message), a titlebar text (“Warning”), a set of buttons the user can then push (in this case just “OK”, MessageBoxButtons.OK), and shows a Warning icon (MessageBoxIcon.Warning), and the last part is really unnecessary with this type of messagebox since there is only one button, but with MessageBoxDefaultButton.Button<1,2 or 3> you can change which button should be default (OK, abort, ignore, retry). Note that 3 is the maximum number of buttons in a messagebox.
When you’ve gotten down that stuff, the function to spit out the first paragraph of text in a matching file should be a walk in the park, as it’s basically the same stuff, only this time working with a standard, or a rich text edit area. These types of components do not use Items, so you cannot add things the same way you would in a listBox. However, adding things in a textbox is still very easy, and you will learn how to use StreamReader with this.
The method, dubbed TextSearch, will take one argument, same as DirSearch, and use the filter the same way, by taking the user input in the searchInput text area. As it should be pretty straight forward after dealing with the DirSearch function, I will just print out how the foreach should look:
void TextSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, txtFile.Text))
{
Pretty much the same as the previous method, as you can clearly see. But now we have to instantiate an object of StreamReader, which is a member of the System.IO namespace, so if you have declared the use of System.IO in your file, it will make things a bit easier. The instantiation of this StreamReader object will be a local one, so it’s done in a particular way: the use of using will be locally, and that is done like this:
using(NameSpace objectName = AnotherNamespace.Function(variable))
This was probably a bit confusing, so let me just show you what you need to do:
using(StreamReader sr = File.OpenText(f))
File.OpenText(variable) is another member of System.IO, and what it does is open UTF-8 encoded files for reading. We will use the standard ReadLine(); function to read these files and print them onto the textarea. One problem you will have, is that ReadLine returns variables of type char and your textarea will only take type string. The solution is annoyingly simple (for me that is, I looked for a whole day until I figured out how to do that). Now, we just add another foreach loop:
foreach (char t in sr.ReadLine())
{
string tt = t.ToString();
lstTextFound.Text += tt;
}
What this does is declare a variable of type char, read a single character in the file opened (variable “f”) using File.OpenText(); and put that character in the char variable “t”. But as stated, textareas cannot handle char type variables, so we have to convert it to a string. This is where the beauty of .NET comes in.
In .NET, every variable is treated like an instance, or an object, so you can manipulate every variable with a “member” method. In this case, ToString(); This method will convert any variable type into a string type, although Beltira has made me note sometimes it will do something completely unexpected, but I suspect this applies only to more advanced things that I, and most likely you, won’t get involved with any time soon. So for now, it works.
Now we have converted the char into string, so now we just need to add it. To ADD anything to a text area, you see we just use += and that will add any value to the assigned textarea.
Also you might have noticed I said we will only print the first paragraph, but there is no code in here to specify it to print just the first paragraph. This is because ReadLine(); will read until it reaches a line that equals null, or nothing. And a blank line equals null, so after the first paragraph, it will read null, and therefor stop reading and assume EOF (End Of File). Great isn’t it? Built in foolproof. Good for preventing the printing of HUGE text files, which would lead to terrible slowdowns. Also it is good to include some blank spaces in the print area of your application, or else it can seem a little cluttered. To do this, just add
lstTextFound.Text += “\r\n”;
Where you find it appropriate. \r is the escape for a carriage return, and \n is the escape for a new line. Note that you need both in this specific context, it might not always be needed.
After you’ve added this last foreach loop, make the method call itself again, and do a catch exception, just in the same way done with the DirSearch(); method. That’s it! You just made a cool C# GUI application!
Resources
Beurocratic mumbo jumbo:
This tutorial copyright 2004 Jay Davidsen, no copying or redistribution of this tutorial, in part or as a whole, is permitted without the express written (digital or handwritten) permission of said author.
Exception:
The code, on its own, however, may be used freely, in any application, in any context, and be redistributed as clear text, executable, or any other formats.






