Check If User Name Exists Using AJAX And C#


You could make sure the user name entered during the registration process of your website is unique before the submit button is clicked using AJAX and C#. To accomplish this create two aspx pages. The first (default.aspx in this example) is the registration page, and it contains a TextBox control with an onkeyup element that calls the updateOutput JavaScript function and a span tag to display the HTML returned by the XMLHttpRequest.send function. The second page (doajaxstuff.aspx) should only contain following tags:

  1. <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="doajaxstuff.aspx.cs"
  2. Inherits="ManualAJAX.doajaxstuff" %>
  3. <asp:literal runat="server" id="literal1" />

The html, title and body tags should be removed because the page contents will be added to the default.aspx page, which already has these tags. The C# code that checks if the user name exists is in the Page_Load event of doajaxstuff.aspx. It gets the user name from the query string and displays the result in a Literal control. To keep the example simple I returned “User name exists” or “OK”, but this could be changed to return an img tag to show a red cross image or a green tick respectively.

string[] usernames = { "admin", "administrator", "user1","user2",
                     "guest1", "guest2"};
protected void Page_Load(object sender, EventArgs e)
{
    string newUsername = Request.QueryString["q"];  

    if(usernames.Contains(newUsername))
    {
        literal1.Text = "User name exists";
    }
    else
    {
        literal1.Text = "OK";
    }
}

The JavaScript code below does the AJAX work. The updateOutput function checks first if the TextBox is empty, and exits if true. Then it creates an object called xmlHttp which is an XMLHttpRequest object or an ActiveXObject, depending on the user’s browser. XMLHttpRequest is supported in browsers from Internet Explorer 6, Opera 7.60, Mozilla 1.0, Netscape 7, Safari 1.2 and Konqueror 3.2. If the user has Internet Explorer 5 an ActiveXObject will be created, which basically does the same job. If the xmlHttp object is created the variable url will be assigned a string containing the page to call plus the query string, which is the string entered by the user in usernameTextBox.

The onreadystatechange event handler is assigned the name of the function StateChanged. This event occurs five times: when the request is initialized, set up, sent, being processed and completed. You could check which stage the request is in using the readyState variable (0, 1, 2, 3 and 4 respectively.) The if statement checks for 4 which is set when the HTML is downloaded to xmlHttp.responseText. The if statement also makes sure that xmlHttp.status is 200, which means no error occurred. If both these conditions are true the contents of xmlHttp.responseText are displayed in the span tag.

The open method sets the parameters of the request and contains three parameters; the request method, the URL of the request and a Boolean parameter that specifies the request should be executed asynchronously or not. The first parameter could be “GET”, “POST”, “HEAD” or “PUT”. The second parameter is the relative or full URL of the page to request. And the third parameter should be true so the page could be called asynchronously.

The send method executes the request. Because the open method’s first parameter is “GET”, send’s parameter is null. If open’s first parameter was “POST” it would be a string containing the request parameters.

Code:

<head runat="server">
<title>Manual AJAX</title>
<script language="javascript" type="text/javascript">
var xmlHttp;
function updateOutput(inputString)
{
if(inputString.length == 0)
{
document.getElementById("output").innerHTML = "";
return;
}
try
{
if(window.XMLHttpRequest)
xmlHttp = new XMLHttpRequest();
else if (window.ActiveXObject)
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
if(!xmlHttp || xmlHttp == null)
{
return;
}
var url="doajaxstuff.aspx?q=" + inputString;
xmlHttp.onreadystatechange=StateChanged;
xmlHttp.open("GET", url, true);
xmlHttp.send(null);
}
catch(e)
{
document.getElementById("output").innerHTML = "An error occured";
}
}
function StateChanged()
{
if((xmlHttp.readyState == 4) && (xmlHttp.status == 200))
{
document.getElementById("output").innerHTML = xmlHttp.responseText;
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
Enter Username:
<asp:TextBox runat="server" ID="usernameTextBox"
onkeyup="updateOutput(this.value)" />
<span id="output"></span>
</div>
</form>
</body>
<head runat="server">     <title>Manual AJAX</title> <script language="javascript" type="text/javascript">         var xmlHttp; function updateOutput(inputString) {             if(inputString.length == 0)  {                 document.getElementById("output").innerHTML = "";   return;             } try  {                 if(window.XMLHttpRequest)       xmlHttp = new XMLHttpRequest();  else if (window.ActiveXObject)     xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");             if(!xmlHttp || xmlHttp == null)  {                     return;                 } var url="doajaxstuff.aspx?q=" + inputString;                 xmlHttp.onreadystatechange=StateChanged;                 xmlHttp.open("GET", url, true);                 xmlHttp.send(null);             }             catch(e)             {                 document.getElementById("output").innerHTML = "An error occured";             }         } function StateChanged() {             if((xmlHttp.readyState == 4) && (xmlHttp.status == 200))  {                 document.getElementById("output").innerHTML = xmlHttp.responseText;             }         }     </script> </head> <body>     <form id="form1" runat="server">     <div>         Enter Username:         <asp:TextBox runat="server" ID="usernameTextBox" onkeyup="updateOutput(this.value)" />         <span id="output"></span>     </div>     </form> </body>

For this example the C# code in the doajaxstuff.aspx page searches an array containing the user names. This could be changed to search through the users in the aspnetdb database using the Membership.GetUser static function. I should also mention that the user can ignore the result of this validation check and submit a name that exists. To prevent this, the same validation should be done in the Submit button’s code.

WPF Dialogs and DialogResult


In WPF Dialogs are quite different from Windows Forms. The behavior is still the same i.e when you have a Dialog opened (by calling the ShowDialog() method) the user must close the dialog in order to use the Window that opened the Dialog Window. The difference is the way you handle the Dialog Result and also how to set Dialog Results.

Let’s say that you created a Window in Windows Forms and you have a Button. You can set the DialogResult property of the button so that when the user click on that button the Dialog ends with the Dialog Result that you have set. (also if the user clicks the exit button of the Dialog the DialogResult would be a Cancel). The code to handle the DialogResult in Windows Forms would look like this.

1: DialogResult result = new Form1().ShowDialog();
   2: if (result == DialogResult.OK)
   3:     MessageBox.Show("User clicked OK");
   4: else if (result == DialogResult.Cancel)
   5:     MessageBox.Show("User clicked Cancel");

In the WPF this is different. There is no DialogResult property on controls and also the ShowDialog does not return a DialogResult instead it returns a Nullable<bool>.

So to handle a DialogResult after calling the ShowDialog() in WPF your code would look like this:

1: MyDialog dialog = new MyDialog();
   2: dialog.ShowDialog();
   3:
   4: if (dialog.DialogResult.HasValue && dialog.DialogResult.Value)
   5:     MessageBox.Show("User clicked OK");
   6: else
   7:     MessageBox.Show("User clicked Cancel");

ShowDialog can return True which is equivalent to DialogResult.Ok or False which is equivalent to DialogResult.Cancel.

So let’s have a look at how you can create a Dialog in WPF and set the DialogResult of the Dialog. We can do this by setting a property on the Window called DialogResult. Once you set this property on the Window the Window will automatically close and the ShowDialog methods returns the result that you have set in the DialogResult property.

If you want to have a “Cancel” Button for your Dialog you can use the IsCancel property and set this to true. When the user clicks the button the DialogResult will be set to false and the Dialog will close. This will also allow the user to click ESC to cancel the dialog ( which is something that every user would expect from a dialog). Please note that if you have more than one button with the IsCancel = “True” the ESC does not work as expected instead the focus will be given to the first button that has the IsCancel = “True”. The XAML for this button would look like this:

 1: <Button Width="100" Content="Cancel" IsCancel="True"/>

If you want to have an “Ok” button you can set the IsDefault property. This property will NOT set the DialogResult to true for you, instead it will allow the user to click “Enter” and the Click event handler of the button is automatically called (so as such it doesn’t really have to do with Dialogs, it is just more useful when you are using Dialogs because users would expect such a behavior). You must code the event handler (and obviously register the handler to the click event) yourself and set the DialogResult to true. Something like this.

1: private void ButtonOkClick(object sender, RoutedEventArgs e)
   2: {
   3:     DialogResult = true;
   4: }

For more information visit: MSDN documentation on this here.

testing


sdasdasd

Post Test from Windows Live Writer


Hello Paul Mercieca!!!!!

Binding a Windows Forms ComboBox in C#


Most often when reading the selected item of a bound combobox you will need more information than just the selected text or the selected index of the combo. For example, if you have a combobox bound to a user table in your database, you will most probably want to have the full user name displayed in the combobox, but when a user is selected you will want to work with the user code or user id. In this case the combo’s selected index is of no use and neither is the display text. You need a way to be able to retrieve the user code when a user is selected.

Fortunately, this is quite easy to accomplish. All we need to do is bind our combobox to a list of KeyValuePair objects. In this article I am going to show you how to do exactly that.

To start off create a form which looks similar to the below one:

Now in the Form_Load event handler we must add the following code:

private void MainForm_Load(object sender, EventArgs e)
{
    // Create a List to store our KeyValuePairs
    List> data = new List>();

    // Add data to the List
    data.Add(new KeyValuePair("p1", "Joe"));
    data.Add(new KeyValuePair("p2", "David"));
    data.Add(new KeyValuePair("p3", "Keith"));
    data.Add(new KeyValuePair("p4", "Andrew"));
    data.Add(new KeyValuePair("p5", "Maria"));

    // Clear the combobox
    cboData.DataSource = null;
    cboData.Items.Clear();

    // Bind the combobox
    cboData.DataSource = new BindingSource(data, null);
    cboData.DisplayMember = "Value";
    cboData.ValueMember = "Key";
}

In the first line of code we are creating a List object to store our KeyValuePair objects. The KeyValuePair class can be very useful since it allows you to create a pair of objects of any type, one of which is the key and the other is the value. What this means is that you can have an object of type string paired with a key of type integer for example. Or you could have a value of type MyClass with a key of type string. The combinations are limitless.

As you can see in the code, we are creating a KeyValuePair where both the key and the value are strings. We are then adding data to the List object by creating KeyValuePair instances and adding them to our List. Next we are clearing the combobox as a precaution (just in case it was populated with something already), and finally we are binding the combobox to the List.

The last two lines of the above code are critical for your binding to work correctly. We must tell the combo which is the DisplayMember and which is the ValueMember of our KeyValuePair so that it will know which object from the pair to display and which to use as the key.

Once you have created the above code run your project and you will see that the combobox is populated with the above names. The key value however cannot be seen, so let’s create some code to visually see the selected key.

Subscribe to the SelectedIndexChanged event of your combobox and add the following code:

private void cboData_SelectedIndexChanged(object sender, EventArgs e)
{
    // Get the selected item in the combobox
    KeyValuePair selectedPair = (KeyValuePair)cboData.SelectedItem;

    // Show selected information on screen
    lblSelectedKey.Text = selectedPair.Key;
    lblSelectedValue.Text = selectedPair.Value;
}

What we are doing here is retrieving the combo’s selected item and converting it to a KeyValuePair object. Then from our KeyValuePair object we are accessing the Key and the Value properties and assigning them to the labels on our form.

Now if you run the application again you should have something like the following, and as you can see the key and value are being displayed in our labels.

Now using this technique you can easily bind a combobox and have one value displayed while another value is used as your key.

Create a Worker Thread for your Windows Form in C#


When performing a relatively heavy operation on your Windows Form, what often happens is that your application’s UI will freeze until the heavy operation completes. This is usually unacceptable because your application’s end user will think it crashed and probably try to close it. To solve this problem you need to run your heavy operation on a separate thread from that of your UI. This way you will be able to run your operation while also keep the end user informed of the progress from the UI. In this article I will show you how to do just that.

First let’s create a form with a textbox which displays the progress of the heavy operation, and two buttons, one to start the process and one to stop it.

Next we need to create our heavy operation method. For this example let’s just create a loop which iterates for 1 million times.

private void HeavyOperation()
{
    // Example heavy operation
    for (int i = 0; i <= 999999; i++)
    {
    }
}

Now let’s declare our thread and a boolean flag used to stop the heavy operation. We must use the System.Threading namespace to access the Thread class.

// Declare our worker thread
private Thread workerThread = null;

// Boolean flag used to stop the
private bool stopProcess = false;

Next in the start button event handler method, we will initialise the thread and tell it to run the HeavyOperation method.

private void btnStart_Click(object sender, EventArgs e)
{
    this.stopProcess = false;

    // Initialise and start worker thread
    this.workerThread = new Thread(new ThreadStart(this.HeavyOperation));
    this.workerThread.Start();
}

Your code should be able to compile and run but you won’t see anything happening because we still have to display the heavy operation’s progress on the UI.

This is where Delegates come in. In .NET a delegate is a form of type-safe function pointer. From the HeavyOperation method which is being run under the worker thread, we cannot access the UI thread directly because it would cause a cross-thread operation exception. This is because the UI thread and our worker thread are running independently of each other and cannot access objects which have not been created by themselves.

So to write to our status textbox which is on the UI from our worker thread, we must use a delegate. At the top of our class declare a delegate and an instance of the delegate as shown below:

// Declare a delegate used to communicate with the UI thread
private delegate void UpdateStatusDelegate();
private UpdateStatusDelegate updateStatusDelegate = null;

Next initialise the delegate in form load for example:

private void Form1_Load(object sender, EventArgs e)
{
    // Initialise the delegate
    this.updateStatusDelegate = new UpdateStatusDelegate(this.UpdateStatus);
}

As you can see in the above code, the delegate is being passed the method name UpdateStatus. This method will be used to display activity indication to the end user. Now let’s create the method:

private void UpdateStatus()
{
    this.txtProgress.Text += "*";
}

Next, let’s update our HeavyOperation method to call the delegate, which updates the status:

private void HeavyOperation()
{
    // Example heavy operation
    for (int i = 0; i <= 999999; i++)
    {
        // Check if Stop button was clicked
        if (!this.stopProcess)
        {
            // Show progress
            this.Invoke(this.updateStatusDelegate);
        }
        else
        {
            // Stop heavy operation
            this.workerThread.Abort();
        }
    }
}

As you can see, to call the delegate we are using the Invoke keyword, which executes the delegate on the UI thread, since we are calling Invoke from the this object.

And to add the final touch to our application, we must add an event handler for the stop button and set the stopProcess flag to true.

private void btnStop_Click(object sender, EventArgs e)
{
    this.stopProcess = true;
}

Now if you run the application and click on your start button, you will see the status textbox filling up with the “*” character. What’s happening is your worker thread is iterating for 1 million times and for each iteration a star is written to the textbox using the delegate.

How to Capture System Events using C#


What are system events? Well, basically they are events raised by the operating system when a user performs an action which affects the operating environment.

System events are accessible through the Microsoft.Win32.SystemEvents class.

SystemEvents Events
Below is a list of all the system events found within the SystemEvents class.

Name Description
DisplaySettingsChanged Occurs when the user changes the display settings.
DisplaySettingsChanging Occurs when the display settings are changing.
EventsThreadShutdown Occurs before the thread that listens for system events is terminated.
InstalledFontsChanged Occurs when the user adds fonts to or removes fonts from the system.
LowMemory Obsolete. Occurs when the system is running out of available RAM.
PaletteChanged Occurs when the user switches to an application that uses a different palette.
PowerModeChanged Occurs when the user suspends or resumes the system.
SessionEnded Occurs when the user is logging off or shutting down the system.
SessionEnding Occurs when the user is trying to log off or shut down the system.
SessionSwitch Occurs when the currently logged-in user has changed.
TimeChanged Occurs when the user changes the time on the system clock.
TimerElapsed Occurs when a windows timer interval has expired.
UserPreferenceChanged Occurs when a user preference has changed.
UserPreferenceChanging Occurs when a user preference is changing.

Note: Some of these system events may not be raised on Windows Vista.

Example Application
As an example let’s create a simple Windows Forms Application and place two buttons and a textbox on the main form. The buttons are going to subscribe and unsubscribe from the system events and the textbox is going to display the captured event details.

In our application we are going to listen for the following four system events: InstalledFontsChanged, DisplaySettingsChanged, TimeChanged, and UserPreferenceChanged. The code for this is shown below:

private bool eventHandlersCreated;

private void btnStartListening_Click(object sender, EventArgs e)
{
    this.StartListening();
}

private void btnStopListening_Click(object sender, EventArgs e)
{
    this.StopListening();
}

private void StartListening()
{
    Microsoft.Win32.SystemEvents.InstalledFontsChanged += new EventHandler(FontHandler);
    Microsoft.Win32.SystemEvents.DisplaySettingsChanged += new EventHandler(ScreenHandler);
    Microsoft.Win32.SystemEvents.TimeChanged += new EventHandler(TimeHandler);
    Microsoft.Win32.SystemEvents.UserPreferenceChanged += new Microsoft.Win32.UserPreferenceChangedEventHandler(PreferenceChangedHandler);

    this.eventHandlersCreated = true;
}

private void StopListening()
{
    Microsoft.Win32.SystemEvents.InstalledFontsChanged -= new EventHandler(FontHandler);
    Microsoft.Win32.SystemEvents.DisplaySettingsChanged -= new EventHandler(ScreenHandler);
    Microsoft.Win32.SystemEvents.TimeChanged -= new EventHandler(TimeHandler);
    Microsoft.Win32.SystemEvents.UserPreferenceChanged -= new Microsoft.Win32.UserPreferenceChangedEventHandler(PreferenceChangedHandler);

    this.eventHandlersCreated = false;
}

As you can see in the StartListening and StopListening methods we are subscribing and unsibscribing to the system events. Each event handler delegate is calling a particular method, and these methods are shown below:

private void FontHandler(object sender, EventArgs e)
{
    txtStatus.Text += string.Format("Installed fonts changed. {0}", Environment.NewLine);
}

private void PreferenceChangedHandler(object sender, Microsoft.Win32.UserPreferenceChangedEventArgs e)
{
    txtStatus.Text += string.Format("You changed a setting: {0} {1}", e.Category.ToString(), Environment.NewLine);
}

private void ScreenHandler(object sender, EventArgs e)
{
    txtStatus.Text += string.Format("Screen resolution changed. {0}", Environment.NewLine);
}

private void TimeHandler(object sender, EventArgs e)
{
    txtStatus.Text += string.Format("System time changed. {0}", Environment.NewLine);
}

If you were to run this application and then go and change the screen resolution for example, the DisplaySettingsChanged event will fire and its delegate will call our ScreenHandler method, and you will see the text Screen resolution changed in the textbox.

Below is a screenshot of our application:

Note: Since these system events are static events, you must make sure you detach your event handlers when disposing your application, or you will end up with memory leaks!

To take care of this memory leak potential problem, when closing our application we are calling the StopListening method to unsubscribe from the event handlers.

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    if (this.eventHandlersCreated)
        this.StopListening();
}

Note: Do not perform time-consuming processing on the same thread that raises a system event handler because it might prevent other applications from functioning.

If your application must perform time-consuming processes, do the processing on a separate worker thread and not on the same thread which raises the system events.

Create and Read Cookies in ASP.NET


Cookies are small pieces of text which are created by websites and stored by the Internet browser in its cache for later use. Typically a cookie would contain information related to a surfer’s session in a particular website, such as the user name, items in a shopping cart, page layout preferences, etc.

When a surfer visits a website, a cookie would be created with his details, and when he returns to the site his details are loaded from the cookie and sent to the website. This can for example, allow the website to identify who the surfer is and load his last session back.

Cookies can be very useful but they are also easily accessible so it’s advisable to never store sensitive data, such as passwords or credit card numbers, in cookies.

In this short article I am going to show you how to create a cookie in ASP.NET, obviously using C#, and then I will also show you how to read your cookie’s value.

First you must create an ASP.NET Web Application, and once that’s done add two buttons and a label to your Default.aspx web form. The first button we will call“Save Cookie” and the second one “Load Cookie”. The label will be used to display the status on-screen.

In the event handler for the “Save Cookie” button we will create a cookie and add astring value to it. The code should look like this:

protected void btnSave_Click(object sender, EventArgs e)
{
    // Create a cookie object
    HttpCookie cookie = new HttpCookie("TestCookie");

    // Set the cookie's value
    cookie.Value = "Paul Mercieca";

    // Set the cookie's expiration date
    cookie.Expires = DateTime.Now.AddDays(7);

    // Add the cookie to the cookie collection
    Response.Cookies.Add(cookie);

    // Display the status
    lblStatus.Text = "Cookie has been created.";
}

The above code is quite simple. We are creating a cookie called “TestCookie” and assigning it my name as a value. Then we are setting an expiry date of 7 days for the cookie. This means that the cookie will remain valid for 7 days from creation. When that period expires the cookie will be deleted by the web browser. Finally we are adding our new cookie to the Response.Cookies collection which is actually an instance of HttpCookieCollection, and we are setting the status label’s text.

Now to read the cookie. To do this we need to access the HttpCookieCollection instance again by calling Request.Cookies as can be seen in the below code:

protected void btnLoad_Click(object sender, EventArgs e)
{
    // Retrieve the cookie from the cookie collection
    HttpCookie cookie = Request.Cookies["TestCookie"];

    // Verify the cookie exists
    if (cookie != null)
    {
        lblStatus.Text = string.Format("Hello {0}", cookie.Value.ToString());
    }
    else
    {
        lblStatus.Text = "Cookie not found.";
    }
}

Again, this code is very straight forward. All we are doing here is retrieving the “TestCookie” and verifying it exists. If it exists we are displaying the cookie’s value, which in this case is my name – “David Azzopardi”, and if it does not exist we are displaying “Cookie not found”.

And there you have it – creating and reading cookies with C# in ASP.NET.

Recursively Search Directories


Listing files from directories and sub-directories is a common requirement for many developers. In this short tutorial I will show you how to do this in two different ways.

The Directory.GetFiles() Method

This first method is by far the easier of the two, but to implement this you must be working with Microsoft .NET Framework version 2.0 or later.

The System.IO.Directory class contains a method called GetFiles(). It returns a string array of full file names for each file it finds. It also accepts a number of parameters which allow you to customize your search. Below are examples of the three overloads for GetFiles().

Here we are getting a string array of all the files within the directory “E:\Music\Dire Straits”.

string[] files = Directory.GetFiles("E:\\Music\\Dire Straits");

Now here we are filtering which files to get by file extension – we are getting only the files with an extension of “.mp3″ from “E:\Music\Dire Straits.”

string[] files = Directory.GetFiles("E:\\Music\\Dire Straits", "*.mp3");

Finally here we are getting all the “.mp3″ files from “E:\Music\Dire Straits” and all its sub-directories.

string[] files = Directory.GetFiles("E:\\Music\\Dire Straits",
                                    "*.mp3",
                                    SearchOption.AllDirectories);

As you can see, the guys from Microsoft have made getting files from directories recursively very easy – it is just one line of code!

Create a Recursive Search Method

If you are running Microsoft .NET Framework 1.1 you will have to create your own method to recursively search your directory since the GetFiles() method does not support the SearchOption overload.

A recursive method is basically a method which calls itself. Recursion is a very useful technique but can also be demanding on memory if the recursion gets too deep.

So, let’s create a recursive method which will search for all “mp3″ files within a given directory and its sub-directories.

private void DirSearchMP3(string directory)
{
    foreach (string dir in Directory.GetDirectories(directory))
    {
        foreach (string file in Directory.GetFiles(dir, "*.mp3"))
        {
            this.files.Add(file);
        }

        this.DirSearchMP3(dir);
    }
}

As you can see in the above example, we are iterating all the directories within the given directory passed as a parameter, and then searching for “.mp3″ files within each directory. Then the DirSearchMP3() method calls itself and starts the whole process again. It keeps doing this until no more sub-directories are found.

Below is the whole file listing for this example.

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;

namespace RecursiveFileSearch
{
    public partial class Form1 : Form
    {
        List files = new List();

        public Form1()
        {
            InitializeComponent();
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            // Search for mp3 files within all sub-directories directories
            this.DirSearchMP3("E:\\Music\\Dire Straits");

            // Search for mp3 files within current directory
            foreach (string file in Directory.GetFiles("E:\\Music\\Dire Straits", "*.mp3"))
            {
                this.files.Add(file);
            }

            // Display all files found
            foreach (string file in this.files)
            {
                Console.WriteLine(file);
            }
        }

        private void DirSearchMP3(string directory)
        {
            foreach (string dir in Directory.GetDirectories(directory))
            {
                foreach (string file in Directory.GetFiles(dir, "*.mp3"))
                {
                    this.files.Add(file);
                }

                this.DirSearchMP3(dir);
            }
        }
    }
}

As you can see from this small tutorial, recursively searching directories is much easier with the .NET 2.0 framework.
Paul