OK, I'm trying to further my understanding of threading. The code below I
wrote as kind of a primer to myself and maybe a template that I could use in
the future. What I tried to do was pass data into a background thread and
get other data out and also update the main thread on which the main form
was created. It seems to work fine. The basic function of the app is
cheesy, I didn't spend any time on exception handling. northwind.mdb has to
be in the root, i.e, C:\ for it to work. What I hope to get out of posting
it is comments such as "this looks wrong," "this looks right," "you should
have done this differently," etc.
Comments _really_ are appreciated.
Eric
Option Strict On
Option Explicit On
Imports System.Threading
Public Class Form1
Inherits System.Windows.Forms.Form
Private connectionString As String =
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\northwind.mdb;User
Id=admin;Password=;"
Private dsOrders As New DataSet
' a delegate sub with the same signature as the private sub DoneCounting
Delegate Sub DoneCountingDelegate(ByVal iCount As Integer, ByVal
dsDataSet As DataSet)
' a delegate sub with the same signature as the private sub
SetTextBoxText
Delegate Sub SetTextBoxTextDelegate(ByVal TextBoxName As TextBox, ByVal
TextBoxText As String)
' a delegate sub with the same signature as the private sub
SetTextBoxText
Delegate Sub SetDataGridDataDelegate(ByVal DataGridName As DataGrid,
ByVal oDataSet As DataSet)
' a delegate function with the same signature as the private function
GetNorthwindDataOrders
Delegate Function GetNorthwindDataOrdersDelegate(ByVal ConnString As
String, ByVal RowsToGet As Integer) As DataSet
' a delegate function with the same signature as the private function
GetNorthwindDataOrders
Delegate Function GetNorthwindOrdersCountDelegate(ByVal ConnString As
String) As Integer
Private Class NorthwindPull
Public DoneDelegate As DoneCountingDelegate
Public setTextDeleagate As SetTextBoxTextDelegate
Public getOrdersDelegate As GetNorthwindDataOrdersDelegate
Public getOrdersCountDelegate As GetNorthwindOrdersCountDelegate
Private m_rowsToGet As Integer
Private m_connString As String
Private m_ordersCount As Integer
Private m_orders As DataSet
Public WriteOnly Property RowsToGet() As Integer
Set(ByVal Value As Integer)
m_rowsToGet = Value
End Set
End Property
Public WriteOnly Property ConnectionString() As String
Set(ByVal Value As String)
m_connString = Value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(ByVal RowsToGet As Integer, ByVal ConnectionString As
String)
m_rowsToGet = RowsToGet
m_connString = ConnectionString
End Sub
' It's the "Begin" method that starts it all when we're calling a
thread
Public Sub Begin()
m_ordersCount = getOrdersCountDelegate(m_connString)
m_orders = getOrdersDelegate(m_connString, m_rowsToGet)
DoneDelegate(m_ordersCount, m_orders)
End Sub
End Class
Public Sub New()
MyBase.New()
InitializeComponent()
End Sub
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
Private components As System.ComponentModel.IContainer
Friend WithEvents OrdersCount As System.Windows.Forms.TextBox
Friend WithEvents Label1 As System.Windows.Forms.Label
Friend WithEvents Label2 As System.Windows.Forms.Label
Friend WithEvents TotalOrders As System.Windows.Forms.TextBox
Friend WithEvents dgOrders As System.Windows.Forms.DataGrid
Friend WithEvents GoCurrent As System.Windows.Forms.Button
Friend WithEvents GoBackground As System.Windows.Forms.Button
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.GoCurrent = New System.Windows.Forms.Button
Me.dgOrders = New System.Windows.Forms.DataGrid
Me.OrdersCount = New System.Windows.Forms.TextBox
Me.Label1 = New System.Windows.Forms.Label
Me.Label2 = New System.Windows.Forms.Label
Me.TotalOrders = New System.Windows.Forms.TextBox
Me.GoBackground = New System.Windows.Forms.Button
CType(Me.dgOrders,
System.ComponentModel.ISupportInitialize).BeginIni t()
Me.SuspendLayout()
Me.GoCurrent.Location = New System.Drawing.Point(32, 8)
Me.GoCurrent.Name = "GoCurrent"
Me.GoCurrent.Size = New System.Drawing.Size(104, 32)
Me.GoCurrent.TabIndex = 0
Me.GoCurrent.Text = "Go Current Thread"
Me.dgOrders.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top
Or System.Windows.Forms.AnchorStyles.Bottom) _
Or System.Windows.Forms.AnchorStyles.Left) _
Or System.Windows.Forms.AnchorStyles.Right),
System.Windows.Forms.AnchorStyles)
Me.dgOrders.DataMember = ""
Me.dgOrders.HeaderForeColor =
System.Drawing.SystemColors.ControlText
Me.dgOrders.Location = New System.Drawing.Point(16, 120)
Me.dgOrders.Name = "dgOrders"
Me.dgOrders.Size = New System.Drawing.Size(260, 144)
Me.dgOrders.TabIndex = 1
Me.OrdersCount.Location = New System.Drawing.Point(184, 64)
Me.OrdersCount.Name = "OrdersCount"
Me.OrdersCount.Size = New System.Drawing.Size(56, 20)
Me.OrdersCount.TabIndex = 2
Me.OrdersCount.Text = "10"
Me.Label1.Location = New System.Drawing.Point(32, 64)
Me.Label1.Name = "Label1"
Me.Label1.Size = New System.Drawing.Size(144, 23)
Me.Label1.TabIndex = 3
Me.Label1.Text = "Retrieve how many orders?"
Me.Label2.Location = New System.Drawing.Point(32, 88)
Me.Label2.Name = "Label2"
Me.Label2.Size = New System.Drawing.Size(144, 23)
Me.Label2.TabIndex = 4
Me.Label2.Text = "Northwind Total Orders"
Me.TotalOrders.Location = New System.Drawing.Point(184, 88)
Me.TotalOrders.Name = "TotalOrders"
Me.TotalOrders.Size = New System.Drawing.Size(56, 20)
Me.TotalOrders.TabIndex = 5
Me.TotalOrders.Text = ""
Me.GoBackground.Location = New System.Drawing.Point(160, 8)
Me.GoBackground.Name = "GoBackground"
Me.GoBackground.Size = New System.Drawing.Size(112, 32)
Me.GoBackground.TabIndex = 6
Me.GoBackground.Text = "Go Background Thread"
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(288, 273)
Me.Controls.Add(Me.GoBackground)
Me.Controls.Add(Me.TotalOrders)
Me.Controls.Add(Me.Label2)
Me.Controls.Add(Me.Label1)
Me.Controls.Add(Me.OrdersCount)
Me.Controls.Add(Me.dgOrders)
Me.Controls.Add(Me.GoCurrent)
Me.Name = "Form1"
Me.Text = "Form1"
CType(Me.dgOrders,
System.ComponentModel.ISupportInitialize).EndInit( )
Me.ResumeLayout(False)
End Sub
' get the data on the current thread
Private Sub GoCurrent_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles GoCurrent.Click
Windows.Forms.Cursor.Current = Cursors.WaitCursor
Dim i As Integer = GetNorthwindOrdersCount(connectionString)
Dim ds As DataSet = GetNorthwindDataOrders(connectionString,
CInt(Me.OrdersCount.Text))
DoneCounting(i, ds)
End Sub
' get the data on a background thread
Private Sub GoBackground_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles GoBackground.Click
Windows.Forms.Cursor.Current = Cursors.WaitCursor
Dim iRows As Integer = CInt(Me.OrdersCount.Text)
Dim np As New NorthwindPull(iRows, connectionString)
np.getOrdersDelegate = AddressOf GetNorthwindDataOrders
np.getOrdersCountDelegate = AddressOf GetNorthwindOrdersCount
np.DoneDelegate = AddressOf DoneCounting
Dim t As New Thread(AddressOf np.Begin)
t.IsBackground = True
t.Start()
End Sub
Private Function GetNorthwindDataOrders(ByVal ConnString As String,
ByVal RowsToGet As Integer) As DataSet
Dim strSQL As String = "SELECT TOP " & RowsToGet & " * FROM orders"
Dim oConn As New System.Data.OleDb.OleDbConnection(ConnString)
Dim daAccess As New System.Data.OleDb.OleDbDataAdapter(strSQL,
oConn)
Dim m_dataSet As New DataSet
daAccess.Fill(m_dataSet, "Orders")
oConn.Close()
oConn.Dispose()
Return m_dataSet
End Function
Private Function GetNorthwindOrdersCount(ByVal ConnString As String) As
Integer
Dim strSQL As String = "SELECT COUNT(*) as Cnt FROM orders"
Dim oConn As New System.Data.OleDb.OleDbConnection(ConnString)
Dim oCmd As New System.Data.OleDb.OleDbCommand(strSQL, oConn)
oConn.Open()
Dim x As Integer = CInt(oCmd.ExecuteScalar)
oConn.Close()
oConn.Dispose()
Return x
End Function
Private Sub DoneCounting(ByVal iCount As Integer, ByVal dsDataSet As
DataSet)
' the textbox TotalOrders has the InvokeRequired property, so I use
it to
' see if we need to call the invoke method
If Me.TotalOrders.InvokeRequired Then
Me.TotalOrders.Invoke( _
New SetTextBoxTextDelegate( _
AddressOf SetTextBoxText), New Object() {TotalOrders,
iCount.ToString})
Else
SetTextBoxText(Me.TotalOrders, iCount.ToString)
End If
' There appears to be no InvokeRequired property of the datagrid.
This probably isn't a problem
Me.dgOrders.Invoke( _
New SetDataGridDataDelegate( _
AddressOf SetDataGridData), New Object() {dgOrders,
dsDataSet})
' is this thread safe?
Windows.Forms.Cursor.Current = Cursors.Default
End Sub
' These 2 subs below were _only_ created because we need to call the
appropriate method
' when we want to write back to the main thread. We will be using the
invoke method.
Public Sub SetTextBoxText(ByVal TextBoxName As TextBox, ByVal
TextBoxText As String)
TextBoxName.Text = TextBoxText
End Sub
Public Sub SetDataGridData(ByVal DataGridName As DataGrid, ByVal
oDataSet As DataSet)
DataGridName.DataSource = oDataSet
DataGridName.DataMember = "Orders"
End Sub
End Class