Simple Multi-Threading

We’ve all installed programs on our computers and seen different things happening on the screen right?
Progress bars counting to 100%… Labels changing to show us what file is being worked on… Did you ever wonder how to do that? If you like essentially useless, but attractive stuff like that as much as I do, you’re answer is definitely going to be “YES!”

Using an installer as an example, the simple theory behind it is that the installer runs on (at least) two different threads. When working with threads, imagine the execution of the application flows like a river; a single passage of the water from point A to point B.
If the river should split down another tributary, though, some of the water goes in a different direction, doesn’t it? That’s what threads do, it basically allows you to split an application up, so that it can do more things at any given time.

Let’s get into a simple example…

The following code opens a connection to a database and writes the selected data into a ListBox control (not a practical application, as most people won’t go looking through a full table’s worth of data in a ListBox, but it shows you what threading actually does quite nicely on the form).
The data access will be done on a separate thread, while another thread counts from 0 while the data access thread is still busy.
So, we’ll have 3 threads:

  1. The main thread that builds and controls the form
  2. The 2nd thread that queries the database and modifies the ListBox
  3. The 3rd thread that makes the Label count while thread 2 is busy

The form will consist of a Button, a Label, and a ListBox. I’m keeping the names of these controls as the Visual Studio defaults for clarity.

‘ Imports and Global Variables
1 Imports System.Threading
2 Imports System.Data
3 Imports System.Data.SqlClient
4  
5 Private DS As New DataSet
6 Private DA As New SqlDataAdapter
7  
8 Private t1 As Thread
9 Private t2 As Thread
10  
11 Private SetTextDelegate As SetTextCallBack = _
New SetTextCallBack(AddressOf SetTextMethod)
12 Private AddItemDelegate As AddItemCallBack = _
New AddItemCallBack(AddressOf AddItemMethod)
13 Delegate Sub SetTextCallBack(ByVal Text As String)
14 Delegate Sub AddItemCallBack(ByVal Item As String)

We’re creating 2 threads here. Thread t1 will perform the data access and add items to the ListBox, and thread t2 will just update the Label’s text while t1 is working. This is just for a visual indication that things are actually working.

I’ve already covered connections to SQL Data Sources in my blog, and, since it’s a lot of code, I won’t be including it in this post. Just know that even though we’re working with threads here, there’s nothing different that needs to be done to the code that connects to the database and populates the dataset.

Next we’re going to write the button click event handler, this is just going to set the threads up and start them.

1 Private Sub Button1_Click(ByVal Sender As Object, ByVal e As System.EventArgs) Handles Me.Button1.Click
2     t1 = New Thread(New ThreadStart(AddressOf GetData))
3     t2 = New Thread(New ThreadStart(AddressOf ProgressCounter))
4     t1.Start
5     t2.Start
6 End Sub

When we set the threads in lines 2 and 3, we use AddressOf to tell the threads what code they’re supposed to handle. Lines 11 – 14 in the global declarations are used for interacting with form elements, because controls can’t be accessed from a thread that they weren’t created on.

Now, let’s write the code that t1 will use:

1 Private Sub GetData()
2     ‘ SQL Data Access code goes here
3 Dim CurrentRow As String = Nothing
4 For i As Integer = 0 To DS.Tables(0).Rows.Count – 1
5     CurrentRow = DS.Tables(0).Rows(i)(1).ToString
6     Thread.Sleep(400)
7      Me.Invoke(Me.AddItemDelegate, New Object() {CurrentRow})
8 Next i
9 End Sub

Here, we’re simply looping through the DataSet, and, on each, we’re storing the value in the specified cell. We’re then passing that value to the delegate sub which will use it to execute the next procedure to add it to the ListBox.

1 Private Sub AddItemMethod(ByVal Item As String)
2     ListBox1.BeginUpdate()
3     ListBox1.Items.Add(Item)
4     ListBox1.EndUpdate()
5 End Sub

That’s it for the first thread. The main part of the application is now done, now, let’s get to the 2nd thread:

1 Private Sub ProgressCounter()
2     Dim i As Integer = 0
3     While Not t1.IsAlive = False
4         Me.Invoke(Me.SetTextDelegate, New Object() {i.ToString})
5         i = i + 1
6     End While
7 End Sub
8  
9 Public Sub SetTextMethod(ByVal Text As String)
10     Label1.Text = Text
11 End Sub

Very simple, we’re just storing an integer value and passing it to our delegate so that the delegate can write it to the label.

Lastly, know that a typical application on a 32-bit platform has capacity for 250 threads. You generally shouldn’t need to use more than 10 though (if that). Managing a lot of threads does become quite a nightmare, so be very sure about what your application needs to do before you go crazy creating threads. Also, don’t worry about writing code to close your threads. They will close themselves when they complete execution (i.e. when they’re done working).

In my next post, I’ll show you how to make a delegate procedure modify the text value of any control on your form, so watch this space!

-L

[ASP.NET] Horizontal Submenu from XML

In my last post I showed you a workaround that allowed you to create a horizontal submenu when you clicked on a MenuItem from another menu on the same page. That example hard-coded the MenuItem definitions into the code file, and I said that I’d be demonstrating how to create a horizontal submenu from a sitemap file. While attempting this, I got hit in the face by an error that has to do with hierarchy which I researched only to find that most people suggest it would be easier to find another alternative rather than try to solve the problem.

My alternative was to create a custom xml file that contains property definitions for the MenuItem class (namely Text and NavigateURL). Here it is:

<name>Visual Basic.NET</name>

1 <?xml version=1.0encoding=utf-8?>
2 <CategoriesMenu>
3 <item>
4 <id>0</id>
5 <name>VBScript</name>
6 <url>~/Articles/List.aspx?t=cat&amp;r=vbs</url>
7 </item>
8 <item>
9 <id>1</id>
10
11 <url>~/Articles/List.aspx?t=cat&amp;r=vbs</url>
12 </item>
13 <item>
14 <id>2</id>
15 <name>ASP.NET</name>
16 <url>~/Articles/List.aspx?t=cat&amp;r=vbs</url>
17 </item>
18 </CategoriesMenu>

Unfortunately, here’s where the frustration kicked in (mostly because I have very little experience working with XML). I had a lot of problems figuring out how to get the right values out of the XML and into my menu where I needed them. Good thing for you, I’ve spared you the aggravation by fighting through it for you.

Basically, we need to select each <name> and <url> element outlined in the XML and use the text inside of those as our menu definition properties. It took a few hours, but I managed it; here’s how:

<col style="width: 760 Continue reading

Visual Basic Guestbook – Part 3

In this last section of the Visual Basic Guestbook code, we’ll explore how to delete entries from the database in the simplest way possible. We’re going to add a section to our view page that we can use to delete the entries.

Now what you’ll find in a lot of guestbooks is a button on each entry that you can select that will delete the entry. I haven’t learnt how to do that yet, so we’ll be using a textbox control and a button. You’ll need to enter the PostID of the entry you want to delete and click the button. So lets get started.

The first thing we want to do is secure the delete function so that not just anyone can remove entries. To do this, we’re going to add a password to the event handler that the user will have to enter before (s)he can see the delete dialog:

NOTE: As opposed to using normal hyperlinks to the DataRepeater on the view page, add buttons for these functions just before the DataRepeater. This will make it easier to get the event handlers organised.

On your page, add the following controls:

txtAdminPass = TextBox
btnVerify = Button
lblStatus = Label
txtEntry = TextBox
btnDelEntry = Button

Add a Page_Load event handler and set the visibility of these controls to false. After you’ve done that, add the following to the click event handler for the delete button:

txtAdminPass.Visible = True
btnVerify.Visible = True

After that, add an event handler for btnVerify:

If  txtAdminPass.Text = “enter_your_password_here” Then
    lblStatus.Visible = True
    lblStatus.Text = “Access granted.”
    lblStatus.Forecolor = Drawing.Color.Green
    txtEntry.Visible = True
    btnDelEntry.Visible = True
Else
    lblStatus.Visible = True
    lblStatus.Text = “Access denied”
    lblStatus.Forecolor = Drawing.Color.Red
End If

This just displays the controls that we’ll use to delete the entry from the database. Now we have to actually delete the entry:

This code goes into the click event handler for btnDelEntry:

Dim con As New SqlConnection(Data Source=.\SQLEXPRESS;” & _
                                                                 “Initial Catalog=Guestbook;” & _
                                                                 “Integrated Security=True;”)

Dim sql As String = “DELETE FROM UserPosts WHERE [PostID] = @Post”

Dim command As New SqlCommand(sql, con)

Dim i As Integer

If Integer.TryParse(txtEntry.Text, i) Then
    con.Open()
    command.Parameters.AddWithValue(“@Post”, Convert.ToInt32(txtEntry.Text))
    command.ExecuteNonQuery()
    con.Close()

    Response.Redirect(“../Default.aspx”)
Else
    lblStatus.Text = “Please enter a numeric value.”
    lblStatus.ForeColor = Drawing.Color.Red
End If

That’s it. Basically all we’re doing here is initially (in the Page_Load) event handler, we’re making sure that the controls meant for deleting entries are hidden. We’re displaying the user verification controls (txtAdminPass, btnVerify) when the user clicks on the delete entry button that’s next to the sign guestbook button. We’re checking user input in the textbox against a value that’s defined in the code. If the user input matches, we’ll display the next set of controls, otherwise, we inform the user that the password entered was incorrect.

To delete the entries, we create the connection, sql command and sql parameter. We’re also creating an integer. The reason we create the integer is so that we can make sure that what the user entered into the txtEntry textbox is an integer. If it is, we delete the entry, if not, we inform the user that only a numeric value can be used.

You’ll notice the difference in the sql parameter to the ones we created in Part 2. This difference basically makes sure that the data entered into the textbox (which is, by default, of the data type string) in converted to an integer.

I’d like to thank you for your time, and for reading my blog. If you’ve got any questions, ask them in comments. Alternatively, head off to http://code.msdn.microsoft.com/netguest and download the application. It installs itself, is lightweight and easy to use.

PLEASE NOTE: If you decide to use my guestbook, but don’t have sa access to the SQL Server on the server that your websie’s hosted on, go into the Default.aspx code file in the root directory of the guestbook and change the uid and pwd parts of the connection string on that page and enter your access details for SQL Server (probably the same username and password you access your website’s control panel with).

-L

Visual Basic Guestbook – Part 2

What with job hunting and doing this and that around the house, I haven’t had much opportunity to write this post and I apologise for the delay.

If you’ll remember, in Part 1, we created the database the guestbook would use and populated it with an entry that will aid us during testing.
In Part 2, we’ll be creating the forms that will allow us to view and sign the guestbook. We’ll deal with deleting entries in the next section.

View Guestbook Entries
On our home page for the guestbook (I’m using Default.aspx), we want to view the guestbook. The best way to do that is by using a Data Repeater which basically displays the data in the database table repeatedly (as it’s name suggests). So the first thing we need to do is add a SQL Data Source to the page, so drag one onto the page and configure the data source using the wizard. For this example, a standard connection string will do (i.e. Data Source=.\SQLEXPRESS; Initial Catalog=Guestbook; Integrated Security=True;). You can view the connection string if you like and proceed in the wizard to select all fields within the table in our database.

Now drag a Data Repeater onto the page and switch to your code view.
We could use the <HeaderTemplate></HeaderTemplate> tags within the data repeater to place our sign and delete links, but I found that if you do it this way, the links become part of the data repeater and you can’t use them in your code file..

The code for your links and data repeater should look like this:
<a href=”Sign.aspx”>Sign Guestbook</a> | <a onclick=”EntryDelete”>Delete Entry</a>
<asp:Data Repeater runat=”server” id=”rptGuestbook” Data Source=”SqlDataSource1″>
    <ItemTemplate>
        <table width=”400px”>
            <tr>
                <td width=”10%”><%#Container.DataItem(“PostID”) %></td>
                <td width=”40%”>Posted By: <%#Container.DataItem(“UserName”) %></td>
                <td width=”25%”><a href=”mailto: <%#Container.DataItem(“Email”) %></td>
                <td width=”25%”><a href=”<%#Container.DataItem(“URL”) %></td>
            </tr>
            <tr><td colspan=”4″><%#Container.DataItem(“Message”) %></td></tr>
        </table>
    </ItemTemplate>

Basically all we’re doing here is to bind the information within the cells to the data in the database. This is made possible by the fact that we linked the Data Repeater to the SQL Data Source we linked to the database.

Sign Guestbook
Now we get to the fun part. Add a page to your project and call it Sign.aspx. Add 4 labels4 textboxes, and 1 button to the page. Arrange them logically and name them as shown below:

Labels Textboxes
lblName txtName
lblEmail txtEmail
lblAddress txtAddress
lblMessage txtMessage
Button
btnSign

Remember to make txtMessage a multiline textbox.

Now right-click on btnSign and add the following code to the event handler that is created:

Dim constr As String = “Data Source=.\SQLEXPRESS;” + _
                                  “Initial Catalog=Guestbook;” + _
                                  “Integrated Security=True;”

Dim con As New SqlConnection(constr)
con.Open()

Dim sql As String = “INSERT INTO UserPosts(UserName, Email, URL, Message) Values(@UserName, @Email, @URL, @Message)

Dim cmd As New SqlCommand(sql, con)
cmd.Parameters.Add(“@UserName”, SqlDbType.varchar, 50)
cmd.Parameters(“@UserName”).Value = txtName.Text
cmd.Parameters.Add(“@Email”, SqlDbType.varchar, 50)
cmd.Parameters(“@Email”).Value = txtEmail.Text
cmd.Parameters.Add(“@URL”, SqlDbType.varchar, 50)
cmd.Parameters(“@URL”).Value = txtAddress.Text
cmd.Parameters.Add(“@Message”, SqlDbType.text)
cmd.Parameters(“@Message”).Value = txtMessage.Text

cmd.ExecuteNonQuery()
con.Close()

Please remember to add your imports at the very top of your code file:
Imports System.Data
Imports System.Data.SqlClient

I haven’t tested this code yet, but I adapted if from a Visual Basic cheat sheet I downloaded as part of training material from Microsoft. To be 100% honest, I’m not entirely sure the application will accept the parameter added for the message field. Although, if this is a problem, just replace the data type in the database with varchar(1000). This might help to keep the database size down.

So that’s it for this section. I’ll try to get the next one out to you soon. I’m just working through the finer details myself 🙂

-L

Learning .NET by yourself isn’t exactly easy, PHP isn’t any easier…

I’ve been trying to learn .NET for a long time now (3-4 years). Because I haven’t had the bandwidth to download training material or even run through training material online, It’s been really hard to learn even the basics!
Heck, I only got a copy of Visual Studio 2005 about a month ago…

A few months ago, I started spending as much time on IRC as possible, in a channel made for web developers. I thought “gee, this might be an awesome place to pick up some learning aids and training material”. It wasn’t. Little did I know that the channel I’d joined was full of PHP developers who (if it weren’t illegal) would go out and brutally assault or even murder every .NET developer they could find.
So I figured that maybe .NET was too complicated and started learning PHP. I’d never lost my love for .NET though and constantly demonstrated how it was superior to PHP at every opportunity. If you’re into PHP, you should’ve stopped reading about a paragraph ago… It’s only going to get worse for you.

For one thing, there are so many symbols and operators and comparative characters that you need to learn in PHP… EVERYTHING goes in brackets or parenthesis and Lord help you if you missed one out because you’ll never find it.
At Microsoft though, the wonderful people who work day and night to deliver the high standard applications and services we have come to expect from the multi-billion dollar empire, have made Visual Basic as near to english as possible, so it’s really easy to read through and learn.

Eventually after getting my hands on Visual Studio 2005, I found Beth Massi’s Visual Basic Forms over Data video series and am currently going through it when I’ve got time.
I suggest that if you want to find top-notch training aids and tools, check out her blog, you WONT be disappointed.

-L