Rog D
asked on
Threading and Having a class update a form control Problem....
I have a function that is currently wrapped up in a Class so I can pass a
variable to it.
This function is going to be threaded out and I would like the class
function to be able to update a control on my form. (Treeview).
Is this possible and how do I do it?
Here is a simplisitc overview of what I am doing...
Public Class Form1
Public Sub Button1_Click
GetDirs()
end sub
Public Sub GetDirs()
Dim dir As String
Dim i As Integer = 1
Dim dirs() As String = Directory.GetDirectories(" P:\")
For Each dir In dirs
Dim t As System.Threading.Thread
dim oListView as new SubClass1
t = New System.Threading.Thread(Ad dressOf
oListView.FileListToListVi ew)
oListView.sFolder = dir
'''' I thought by passing the Treeview1 control I could update
it in the class...
oListView.tView = TreeView1
t.Start()
i += 1
ProgressBar1.Value = 100 * (i / CLng(UBound(dirs)))
Next
End Sub
end class
Public Class SubClass1
Public sFolder as string
public tView as treeview
public sub FileListToListView
'''' **** Here is where I want to update the Form1.treeview1 control
tview.nodes.add(sFolder)
end sub
end class
variable to it.
This function is going to be threaded out and I would like the class
function to be able to update a control on my form. (Treeview).
Is this possible and how do I do it?
Here is a simplisitc overview of what I am doing...
Public Class Form1
Public Sub Button1_Click
GetDirs()
end sub
Public Sub GetDirs()
Dim dir As String
Dim i As Integer = 1
Dim dirs() As String = Directory.GetDirectories("
For Each dir In dirs
Dim t As System.Threading.Thread
dim oListView as new SubClass1
t = New System.Threading.Thread(Ad
oListView.FileListToListVi
oListView.sFolder = dir
'''' I thought by passing the Treeview1 control I could update
it in the class...
oListView.tView = TreeView1
t.Start()
i += 1
ProgressBar1.Value = 100 * (i / CLng(UBound(dirs)))
Next
End Sub
end class
Public Class SubClass1
Public sFolder as string
public tView as treeview
public sub FileListToListView
'''' **** Here is where I want to update the Form1.treeview1 control
tview.nodes.add(sFolder)
end sub
end class
What your doing should work though. Try throwing in a Refresh and DoEvents after you update the TreeView:
tview.nodes.add(sFolder)
tview.Refresh()
Aplication.DoEvents()
~IM
tview.nodes.add(sFolder)
tview.Refresh()
Aplication.DoEvents()
~IM
Now, let me explain why this works.
You can't pass the treeview to the thread, because there is no way to pass it by reference. The thread and the form that owns the treeview are two different processes in a sense. What you can do, is pass a delegate object to a constructor of a class - which allows another object to invoke function calls on behalf of your form.
After that, all we have to do is start a thread based on our second object (which has the delegate object) and when the time comes to update the treeview, we invoke the delegate - which will call the function on the form.
You can't pass the treeview to the thread, because there is no way to pass it by reference. The thread and the form that owns the treeview are two different processes in a sense. What you can do, is pass a delegate object to a constructor of a class - which allows another object to invoke function calls on behalf of your form.
After that, all we have to do is start a thread based on our second object (which has the delegate object) and when the time comes to update the treeview, we invoke the delegate - which will call the function on the form.
ASKER
kGreg,
This works great, but one problem is the application closes automatically when Run. I am not calling anything to cause a close of application. Any suggestions. Do I need to have some clean up code when the threads are done?
I am very new to threading.
'' *** Here is where I call start the threads
Public Sub GetDirs()
Dim dir As String
Dim i As Integer = 1
Dim dirs() As String = Directory.GetDirectories(" P:\")
ProgressBar1.Maximum = dirs.Length
For Each dir In dirs
Dim objThread As Threading.Thread
Dim objProcess As New MyThreadClass(New UpdateTreeviewHandler(Addr essOf UpdateTreeview_Callback))
objThread = New Threading.Thread(AddressOf objProcess.Process)
objProcess.sFolder = dir
objThread.Name = dir
objThread.Start()
i += 1
ProgressBar1.Value = ProgressBar1.Value + 1
Next
End Sub
'''''' **** THis was added to the form code as explained above....
Delegate Sub UpdateTreeviewHandler(ByVa l sFolder As String)
Private Sub UpdateTreeview_Callback(By Val sFolder As String)
If Me.InvokeRequired Then
'*** switch over to primary UI thread
Dim handler As New UpdateTreeviewHandler(Addr essOf UpdateTreeview_Implementat ion)
Dim args() As Object = {sFolder}
Me.BeginInvoke(handler, args)
Else
'*** direct call - already running on primary UI thread
UpdateTreeview_Implementat ion(sFolde r)
End If
End Sub
Private Sub UpdateTreeview_Implementat ion(ByVal sFolder As String)
TreeView1.Nodes.Add(sFolde r)
Application.DoEvents()
End Sub
''''' ***** This added to another class...
Public Class MyThreadClass
Private delHandler As Form1.UpdateTreeviewHandle r
Public sFolder As String
Public Sub New(ByVal delHandler As Form1.UpdateTreeviewHandle r)
Me.delHandler = delHandler
End Sub
Public Sub Process()
'
' This is the code your thread performs..
'
delHandler.BeginInvoke(sFo lder, Nothing, Nothing)
End Sub
End Class
This works great, but one problem is the application closes automatically when Run. I am not calling anything to cause a close of application. Any suggestions. Do I need to have some clean up code when the threads are done?
I am very new to threading.
'' *** Here is where I call start the threads
Public Sub GetDirs()
Dim dir As String
Dim i As Integer = 1
Dim dirs() As String = Directory.GetDirectories("
ProgressBar1.Maximum = dirs.Length
For Each dir In dirs
Dim objThread As Threading.Thread
Dim objProcess As New MyThreadClass(New UpdateTreeviewHandler(Addr
objThread = New Threading.Thread(AddressOf
objProcess.sFolder = dir
objThread.Name = dir
objThread.Start()
i += 1
ProgressBar1.Value = ProgressBar1.Value + 1
Next
End Sub
'''''' **** THis was added to the form code as explained above....
Delegate Sub UpdateTreeviewHandler(ByVa
Private Sub UpdateTreeview_Callback(By
If Me.InvokeRequired Then
'*** switch over to primary UI thread
Dim handler As New UpdateTreeviewHandler(Addr
Dim args() As Object = {sFolder}
Me.BeginInvoke(handler, args)
Else
'*** direct call - already running on primary UI thread
UpdateTreeview_Implementat
End If
End Sub
Private Sub UpdateTreeview_Implementat
TreeView1.Nodes.Add(sFolde
Application.DoEvents()
End Sub
''''' ***** This added to another class...
Public Class MyThreadClass
Private delHandler As Form1.UpdateTreeviewHandle
Public sFolder As String
Public Sub New(ByVal delHandler As Form1.UpdateTreeviewHandle
Me.delHandler = delHandler
End Sub
Public Sub Process()
'
' This is the code your thread performs..
'
delHandler.BeginInvoke(sFo
End Sub
End Class
ASKER
Ok. Program works fine when not running in IDE...
Now I have added 100 more points to someone who can help me now change the program above to add a node instead of a "String"
Meaning. In the thread I am building a TreeNode with SubNodes and would like to add the Node with Subnodes to the tree. I thought this would be easy change from what I asked before and it probably is.
Thanks,
Rog
Now I have added 100 more points to someone who can help me now change the program above to add a node instead of a "String"
Meaning. In the thread I am building a TreeNode with SubNodes and would like to add the Node with Subnodes to the tree. I thought this would be easy change from what I asked before and it probably is.
Thanks,
Rog
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
KGreg,
One quick question...
What I am trying to do is fill several nodes with subnodes, then pass this parent node to the ui to be updated.
If possible what changes would need to be made in your code above to accomidate a node with subnodes rather than the "String" being passed?
Thanks,
Roger
One quick question...
What I am trying to do is fill several nodes with subnodes, then pass this parent node to the ui to be updated.
If possible what changes would need to be made in your code above to accomidate a node with subnodes rather than the "String" being passed?
Thanks,
Roger
I'm assuming the goal is to create a node, add a structure of sub-nodes, and pass the parent node to the UI so it can be added.
All you need to do is build your node structure in the Process() procedure. When the node has been built, invoke the delegate and pass in the node. The UI will then add the node to the Nodes collection of the treeview and all will be well in Treeview land.
Here's the code:
''''' **** THis was added to the form code as explained above....
Delegate Sub UpdateTreeviewHandler(ByVa
' This is called when the delegate is invoked
Private Sub UpdateTreeview_Callback(By
If Me.InvokeRequired Then
'*** switch over to primary UI thread
Dim handler As New UpdateTreeviewHandler(Addr
Dim args() As Object = {objNode}
Me.BeginInvoke(handler, args)
Else
'*** direct call - already running on primary UI thread
UpdateTreeview_Implementat
End If
End Sub
' This is called after the context is set to the UI by our delegate function
' It allows the UI to be updated..
Private Sub UpdateTreeview_Implementat
'
' Add the node to the treeview..
'
TreeView1.Nodes.Add(objNod
Application.DoEvents()
End Sub
''''' ***** This added to another class...
Public Class MyThreadClass
Private delHandler As Form1.UpdateTreeviewHandle
Public sFolder As String
Public Sub New(ByVal delHandler As Form1.UpdateTreeviewHandle
Me.delHandler = delHandler
End Sub
Public Sub Process()
'
' Create your node structure..
'
dim node as new TreeNode("Parent Node")
node.Nodes.add(New TreeNode("Child Node")
' etc...
'
' Invoke the delegate and pass in the node structure you've created..
'
delHandler.BeginInvoke(nod
End Sub
End Class
Hope this helps,
KGREG
ASKER
Thanks...
Works great!
Works great!
You're welcome! I'm glad it worked for you
KGREG
KGREG
Delegate Sub UpdateTreeviewHandler(ByVa
Private Sub UpdateTreeview_Callback(By
If Me.InvokeRequired Then
'*** switch over to primary UI thread
Dim handler As New UpdateTreeviewHandler(Addr
Dim args() As Object = {sFolder}
Me.BeginInvoke(handler, args)
Else
'*** direct call - already running on primary UI thread
UpdateUI_Implementation(sF
End If
End Sub
Private Sub UpdateTreeview_Implementat
MyTreeview.Nodes.Add(sFold
Application.DoEvents()
End Sub
This next class will be the object that holds a delegate to the callback functions:
Public Class MyThreadClass
Private delHandler As frmMain.UpdateTreeviewHand
Public Sub New(ByVal delHandler As frmMain.UpdateTreeviewHand
Me.delHandler = delHandler
End Sub
Public Sub Process()
'
' This is the code your thread performs..
'
delHandler.BeginInvoke(sFo
End Sub
End Class
Finally, on the form, do this to create the thread:
dim objThread as Threading.Thread
dim objProcess as new MyThreadClass(New UpdateTreeviewHandler(Addr
objThread = New Threading.Thread(AddressOf
Hope this helps!
KGREG