| ||
|
Most Users Already Use Threads As you already may know, your Pocket PC can load, run and maintain several applications simultaneously. For example, you can download email, listen to music using the Windows Media Player while you at the same time check the last monthly report in Pocket Excel. This multitasking feature of Windows CE works also within one and the same application. Some examples of creating multiple threads within one application include: There are many more valuable scenarios where multithreading adds capabilities and responsiveness. This article will provide a more detailed focus on how to add responsiveness to your user interface dealings. No Magic Silver Bullet The Pocket PC has only one processor. The processor can only execute one instruction at the time. To provide multitasking between different threads, Windows CE allocates a time slice to one thread at the time. The executing thread is put on hold when its time slice is up, and the next thread starts. A time slice is short, so on the surface it looks as if threads execute at the same time. However, creating a new thread for every application procedure is a seriously bad idea: Threading is, as you can see, not the Performance Magic Silver Bullet you would perhaps want it to be. The Key: System.Threading The .NET Compact Framework provides the key to the operating system threading capabilities through the System.Threading classes. Some classes, methods, properties, and events are missing from the full .NET Framework, which is to be expected. The fundamental feature set is, however, intact and exposes the key functionality necessary to commence multithreaded application development. The following types are available: The main type is the Thread type, which implements the following interface: Instance Constructor: (ThreadStart start) Properties: Methods: Let's take a look at how it all works! Threads Anyplace Sample This article's sample project, "Threads Anyplace" is intended to show how to use multithreading to create a more responsive application. Most applications have to deal with populating user interface with data as well as deal with user input. User interface code often executes as forms are loaded, filling list boxes and other controls with data. When this process has finished executing, and only then, the user can continue working with the application and start entering data. The time it takes to populate the user interface is the time the user has to wait. "Threads Anyplace" implements a user interface class that is responsible for filling controls with data. The application uses three controls: a list box, a drop down combo box, and a text box. While the list box and combo box is populated on separate threads, the user can continue to enter data in the text box on the application’s main thread. Starting a separate thread is quite straightforward and is done when the Thread type is instantiated using the following syntax: Thread(AddressOf method)The reason why I have chosen to implement the user interface class is primarily to show how to pass data to a new thread. You can not pass data to the new thread when the thread is constructed. If you need to pass data to a new thread that it needs to execute, you need to put the method referenced in the AddressOf parameter, in a separate class. When the separate class is instantiated before the thread you can pass the data by setting property values. When all data is passed to the class, you can then instantiate the thread with the appropriate method call. The sample application uses one form: ![]() Threads Anyplace Sample To show how much more responsive the application becomes when using multiple threads; I have implemented the same user interface population on one and the same thread. Once again I hope to win first prize in any user interface competition! Code Walkthrough The following code executes when the user taps the Populate-button:
Private Sub btnPopulate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPopulate.Click
' Variables
Dim UI As New UserInterface
' Set User Interface properties
UI.ComboBox = Me.cmbProducts
UI.ListBox = Me.lstSuppliers
' Turn on wait cursor
Cursor.Current = Cursors.WaitCursor
Try
If radMainThread.Checked = True Then
UI.PopulateCombo()
UI.PopulateListbox()
Else
' Create thread to populate the combobox
trd = New Thread(AddressOf UI.PopulateCombo)
trd.Start()
' Create thread to populate the listbox
trd = New Thread(AddressOf UI.PopulateListbox)
trd.Start()
End If
Catch ex As Exception
MsgBox(ex.Message)
Finally
' Turn off wait cursor
Cursor.Current = Cursors.Default
End Try
End Sub
In this sample, I pass the list box control and combo box control to the user interface class by setting
the class properties ComboBox and ListBox. My plan is to implement a generic user interface helper class
which could prove useful from many perspectives. One obvious benefit to implement a user interface helper
class is that it becomes a relevant place to put the code solving the ID/Description pairing, which is an
issue every time a list box or combo box is populated.
The user interface class looks like this:
Public Class UserInterface
Private mComboBox As ComboBox
Private mListBox As ListBox
Public Property ComboBox() As ComboBox
Get
Return mComboBox
End Get
Set(ByVal Value As ComboBox)
mComboBox = Value
End Set
End Property
Public Property ListBox() As ListBox
Get
Return mListBox
End Get
Set(ByVal Value As ListBox)
mListBox = Value
End Set
End Property
Public Sub PopulateCombo()
' Variables
Dim cmd As New SqlCeCommand("SELECT ProductName FROM Products", frmThreadsAnyplace.cn)
Dim dr As SqlCeDataReader
mComboBox.Items.Clear()
Try
' Execute the reader
dr = cmd.ExecuteReader()
' Populate the combo box
While dr.Read()
mComboBox.Items.Add(dr("ProductName"))
End While
mComboBox.SelectedIndex = 0
Catch ex As SqlCeException
MsgBox(ex.Message)
Finally
End Try
End Sub
Public Sub PopulateListbox()
' Variables
Dim cmd As New SqlCeCommand("SELECT CompanyName FROM Suppliers", frmThreadsAnyplace.cn)
Dim dr As SqlCeDataReader
mListBox.Items.Clear()
Try
' Execute the reader
dr = cmd.ExecuteReader()
' Populate the combo box
While dr.Read()
mListBox.Items.Add(dr("CompanyName"))
End While
mListBox.SelectedIndex = 0
Catch ex As SqlCeException
MsgBox(ex.Message)
Finally
End Try
End Sub
End Class
There are certainly more steps necessary to take before this class can be used generically; abstracting
SQL-statements being one of them. Go for it!
Conclusion I hope this article will help you getting started building more responsive multithreaded applications. If you manage and deal the risks involved appropriately you can start leveraging the operating system's threading capabilities, replacing wait cursors with more power. Any comments? |
||||||||||||||||||||||||||
| ©2001-2009 Christian Forsberg & Andreas Sjöström |
||