Stuck on changing UI elements from a different thread

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
Few years ago I started to write small application in vb.net, just for the fun of it.
My following question if probably not hard to answer, but I am stuck on it.
My VB.Net 2010 is a form application, and its purpose is to clean files.
For now the program contains 2 files:
- Main.vb (the form)
- clsStyles.vb (contains class "clsStyles" which contains the cleaning functions)
The form contains a few buttons, a textbox and a StatusStrip. The statusstrip contains a textfield and a progress bar.
The way it is supposed to work is that the user selects the file that needs cleaning, the click on an action button to start the actual cleaning.
I already got everything working without using threading, but then my GUI is not updated when the code it running. Therefore I would like to use multithreading. Only problem is that I am new to multithreading and I get confused by all the different examples, all doing something in a different way.Option Explicit On
Imports System
Imports Microsoft.Win32
Imports System.Threading
Imports System.Timers

Public Class Main
Define global variables
Private FilePath As String
Private aTimer As System.Timers.Timer

Public Shared thdStyles As Thread

<summary>
Handles the loadinf of the form to set handlers etc.
</summary>
<remarks></remarks>
Private Sub Initialize() Handles MyBase.Load
Handlers to execute cleanup code at program shutdown
AddHandler SystemEvents.SessionEnding, AddressOf OnShuttingdown
AddHandler SystemEvents.SessionEnded, AddressOf OnShutdown

Disable path textbox
tbPath.Enabled = False

Set status text
StatusText.Text = "KSS Tools by Eric Mulder"

Create a timer with a three second interval
aTimer = New System.Timers.Timer()
aTimer.Interval = 2000
aTimer.Enabled = True

Hook up the Elapsed event for the timer.
AddHandler aTimer.Elapsed, AddressOf OnTimedEvent

Start the timer
aTimer.Start()
End Sub

Private Sub OnTimedEvent(ByVal source As Object, ByVal e As ElapsedEventArgs)
aTimer.Stop()
SetProgressText("Select a file and pick your action")
End Sub

<summary>
Handles the click event of the location select button
</summary>
<param name="sender </param>
<param name="e </param>
<remarks></remarks>
Private Sub btnSelectFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSelectFile.Click
OpenFileDialog1.DefaultExt = "*.kss"
OpenFileDialog1.Filter = "SynEnergy Project Files (*.kss)|*.kss"
OpenFileDialog1.ShowDialog()
End Sub

<summary>
Handles the click event of the file location confirmation button
</summary>
<param name="sender </param>
<param name="e </param>
<remarks></remarks>
Private Sub OpenFileDialog1_FileOk(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog1.FileOk
FilePath = OpenFileDialog1.FileName
tbPath.Text = FilePath
End Sub

<summary>
Updates the progress text in the statusbar of the form
</summary>
<param name="Text The text to parse</param>
<remarks></remarks>
Public Sub SetProgressText(ByVal Text As String)
What to do in case of an error
On Error GoTo ErrorHandler

Me.StatusText.Text = Text
Exit Sub

ErrorHandler:
MsgBox("There was an error setting the progress text! " & Err.Description, MsgBoxStyle.Critical)
Err.Clear()
On Error GoTo 0
End Sub

<summary>
Calculates the percentage of a value related to the minimum and maximum value
</summary>
<param name="Min Lowest value in the range</param>
<param name="Max Highest value in the range</param>
<param name="CurrVal Current value</param>
<remarks></remarks>
Public Sub SetProgressPerc(ByVal Min As Long, ByVal Max As Long, ByVal CurrVal As Long)
Define local variable containing %
Dim iPercentage As Double

What to do in case of an error
On Error GoTo ErrorHandler

Avoid wrong values ending up in faulty calculations
If Max < Min Then
MsgBox("Invalid values are supplied to calculate the percentage. Check your code!", MsgBoxStyle.Critical)
Exit Sub
End If

Calculate percentage of progress
iPercentage = (Max - Min) / Max * 100

Me.ProgressBar.Value = iPercentage
Exit Sub

ErrorHandler:
MsgBox("There was an error calculating the progress percentage! " & Err.Description, MsgBoxStyle.Critical)
Err.Clear()
On Error GoTo 0
End Sub

<summary>
Handles the click event of the "Clean styles" button.
The function starts a new thread to run the code on.
</summary>
<param name="sender </param>
<param name="e </param>
<remarks></remarks>
Private Sub btnStartStyleCleaning_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStartStyleCleaning.Click
Validate file path
If Me.FilePath = "" Then
MsgBox("You havent selected a file. Please select a file first!", MsgBoxStyle.Exclamation)
Exit Sub
End If

Create a new object refering to the class containing the style cleaning functions
Dim objStyles As New clsStyles()
thdStyles = New Thread(AddressOf objStyles.CleanStyles)
objStyles.FilePath = Me.FilePath
thdStyles.Start()
End Sub
End Class

The last sub in the code above handles the click event of the action button to clean up the file.
I create an object of the clsStyles class to be able to parse the path to the file the user selected. I then define the thread and start it.
From this moment on the code to clean the files should be running inside a separate thread.
The class mentioned above contains (stripped down to problem part):Option Explicit On
Imports Excel = Microsoft.Office.Interop.Excel

Class clsStyles
DEBUGGING VARIABLE. FOR PROGRAMMER ONLY
Protected DEBUG As Boolean = False

Public FilePath As String

<summary>
Removes all unused styles from the active workbook. Preserves the default Excel styles.
Unused means no ranges are currently set to that style. If you need to preserve any styles that are not currently in use, add their names to the initial style array.
</summary>
<remarks></remarks>
Public Sub CleanStyles()
What to do when an error occurs
On Error GoTo ErrorHandler
Update statusbar with progress
Main.SetProgressText("Phase 1/3: Checking file (this can take some time)")
Update progress bar %
Main.SetProgressPerc(0, lTotalStyles, lProgress)
Exit Sub

ErrorHandler:
MsgBox("There was an error while cleaning styles! " & Err.Description, MsgBoxStyle.Critical)
Err.Clear()
On Error GoTo 0
End Sub
When the code runs, it doesnt throw an error, but the GUI elements are not updated either.
What am I doing wrong here? Can anyone point me in the right direction?EDIT: I would like to use "normal" threading instead of the backgroundworker because the application will be extended (in the near future) with other file functions, hence the use of classes.

View the full article
 
Back
Top