[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1268
  • Last Modified:

Backgroundworker VB.Net

Hello -
I do mostly asp.net development, but for this project I need to audit the files on a server. Since this process will likely take a long time and cannot be run during business hours, I need to be able to start and stop the process. Additionally, I want to be able to show the user the progress of the audit on the windows form. I believe I should use a backgroundworker to start and stop the program, and I have some examples to go by, but each one of the examples uses the initializing form for all of the coding and the code I need to run is in a separate class.
Can someone please point me in the right direction to combine the working form code below by calling the separate class code and updating the form. So, instead of the For Next loop in the DoWork sub it would call the class code.
Thanks
'Form code:
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        btnStart.Enabled = False
        btnCancel.Enabled = True
        lstValues.Items.Clear()
        prgThread.Value = 0
        TestWorker = New System.ComponentModel.BackgroundWorker
        TestWorker.WorkerReportsProgress = True
        TestWorker.WorkerSupportsCancellation = True
        TestWorker.RunWorkerAsync()
 
    End Sub
 
    Private Sub TestWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles TestWorker.DoWork
        Dim ListText As String
        For Value As Integer = 0 To 100
            If TestWorker.CancellationPending Then
                Exit For
            End If
            ListText = String.Concat("Item #", Value)
            TestWorker.ReportProgress(Value, ListText)
            Threading.Thread.Sleep(100)
        Next
    End Sub
 
    Private Sub TestWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles TestWorker.ProgressChanged
        prgThread.Value = e.ProgressPercentage
        lstValues.Items.Add(e.UserState)
    End Sub
 
    Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
        TestWorker.CancelAsync()
 
    End Sub
 
    Private Sub TestWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles TestWorker.RunWorkerCompleted
        btnStart.Enabled = True
        btnCancel.Enabled = False
    End Sub
'==============================================================
'Class code:
 
    Public Event CountProgress(ByVal sender As Object, ByVal currentNumber As Integer)
 
    Public Function CountNumbers() As Boolean
        _currentNumber = _startNumber
        Do While _currentNumber < _endNumber
 
            RaiseEvent CountProgress(Me, _currentNumber)
            _currentNumber += 1
 
        Loop
 
    End Function

Open in new window

0
pdf-wbd
Asked:
pdf-wbd
  • 4
  • 4
1 Solution
 
Éric MoreauSenior .Net ConsultantCommented:
0
 
carlnorrbomCommented:
Hi,

The tricky part is: how do you measure the progress of the code execution in the separate class? You would need some means of notification on progress. Do you have access to the class which you need to run and can change / add code? Does it contain events you can subscribe to?

/Carl.
0
 
pdf-wbdAuthor Commented:
Carl - I have complete access to the class doing the work. I will be updating a database with the current record I am checking and in turn want to display this to the user. Prior to the need for stopping and starting, I simply used a raise event back to the form. That is the real question now - how can I get that event to work in the same thread as the background worker?
0
Free learning courses: Active Directory Deep Dive

Get a firm grasp on your IT environment when you learn Active Directory best practices with Veeam! Watch all, or choose any amount, of this three-part webinar series to improve your skills. From the basics to virtualization and backup, we got you covered.

 
carlnorrbomCommented:
Hi,

What is the event name and how is it constructed? What are the parameters? Is the event raised at class level for every pass in the code?

/Carl.
0
 
pdf-wbdAuthor Commented:
Carl - If you were to look at the class code above you'll see a public event called CountProgress that is hit every time it goes through the For Next loop.
Thanks
0
 
carlnorrbomCommented:
Hi,

Please look at the attached code as an example of how to implement something in line with what You want. I put Your event in a class library and built it as a dll and added it as a reference to a simple test project. The code for  both the class library and the test project is attached. It features start, pause and resume of methods in an external class library.

Hope this helps.

/Carl.
WorkerClass.dll:
 
Public Class Methods
 
    Public Shared Event CountProgress(ByVal progress As Integer)
 
    Private Shared _currentNumber As Integer
    Private Shared _startNumber As Integer
    Private Shared _endNumber As Integer
 
    Public Shared Property StartNumber() As Integer
        Get
            Return _startNumber
        End Get
        Set(ByVal value As Integer)
            _startNumber = value
        End Set
    End Property
 
    Public Shared Property EndNumber() As Integer
        Get
            Return _endNumber
        End Get
        Set(ByVal value As Integer)
            _endNumber = value
        End Set
    End Property
 
    Public Shared Function CountNumbers() As Boolean
 
        _currentNumber = _startNumber
 
        Dim progress As Integer = 0
 
        Do While _currentNumber <= _endNumber
            progress = CInt((_currentNumber / _endNumber) * 100)
            RaiseEvent CountProgress(progress)
            _currentNumber += 1
            Threading.Thread.Sleep(100)
        Loop
 
    End Function
 
End Class
 
Form1.vb:
 
Imports WorkerClass.Methods
Imports System.Threading
 
Public Class Form1
 
    Private wThread As New Thread(New ThreadStart(AddressOf StartWorkProcessFromClass))
 
    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        btnStart.Enabled = False
        wThread.Start()
    End Sub
 
    Private Sub btnPause_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPause.Click
        wThread.Suspend()
    End Sub
 
    Private Sub btnResume_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnResume.Click
        wThread.Resume()
    End Sub
 
    Private Sub StartWorkProcessFromClass()
        AddHandler CountProgress, AddressOf UpdateProgress
        wThread.IsBackground = True
        StartNumber = 0
        EndNumber = 100
        CountNumbers()
    End Sub
 
    Private Sub UpdateProgress(ByVal Progress As Integer)
        ProgressBar1.Value = Progress
        If Progress = 100 Then
            btnStart.Enabled = True
            wThread = Nothing
            wThread = New Thread(New ThreadStart(AddressOf StartWorkProcessFromClass))
        End If
    End Sub
 
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Control.CheckForIllegalCrossThreadCalls = False 'Not for production, use InvokeRequired.
    End Sub
 
End Class

Open in new window

ScreenShotTestApplication.png
0
 
pdf-wbdAuthor Commented:
Carl -
This is perfect. Thank you so much. Now I need to understand it so I can add something.....
I want to be able to update a label on the form with the current count (this will eventually report the current file being audited back to the user). So I add an event to the class -
Public Shared Event CurrentCount(ByVal currentNumber As Integer)
Then in the CountNumber Function I raise the event:
RaiseEvent CurrentCount(_currentNumber)

Question is how that gets received by the form?  I see you have a handler in the StartWorkProcessFromClass Sub:
 AddHandler CountProgress, AddressOf UpdateProgress
If I simply add another handler like this:
AddHandler CurrentCount, AddressOf UpdateCount
it states 'CurrentCount' is not an event of 'ThreadProject.frmExperts'

So, where is the CountProgress event being seen by the form? And how do I add another handler for the UpdateCount?

form code:
Imports System.Threading
Imports ThreadProject.WorkerClass
 
Public Class frmExperts
    Private wThread As New Thread(New ThreadStart(AddressOf StartWorkProcessFromClass))
 
    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        btnStart.Enabled = False
        wThread.Start()
    End Sub
 
    Private Sub btnPause_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPause.Click
        wThread.Suspend()
    End Sub
 
    Private Sub btnResume_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnResume.Click
        wThread.Resume()
    End Sub
 
    Private Sub StartWorkProcessFromClass()
        AddHandler CountProgress, AddressOf UpdateProgress
        AddHandler CurrentCount, AddressOf UpdateCount
        wThread.IsBackground = True
        StartNumber = 0
        EndNumber = 100
        CountNumbers()
    End Sub
 
    Private Sub UpdateProgress(ByVal Progress As Integer)
        ProgressBar1.Value = Progress
        If Progress = 100 Then
            btnStart.Enabled = True
            wThread = Nothing
            wThread = New Thread(New ThreadStart(AddressOf StartWorkProcessFromClass))
        End If
    End Sub
 
    Private Sub UpdateCount(ByVal CurrentNumber As Integer)
        lblCurrentCount.Text = CurrentNumber
    End Sub
    Private Sub frmExperts_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Control.CheckForIllegalCrossThreadCalls = False 'Not for production, use InvokeRequired.
 
    End Sub
End Class
 
Class code:
 
Public Class Methods
 
    Public Shared Event CountProgress(ByVal progress As Integer)
    Public Shared Event CurrentCount(ByVal currentNumber As Integer)
 
    Private Shared _currentNumber As Integer
    Private Shared _startNumber As Integer
    Private Shared _endNumber As Integer
 
    Public Shared Property StartNumber() As Integer
        Get
            Return _startNumber
        End Get
        Set(ByVal value As Integer)
            _startNumber = value
        End Set
    End Property
 
    Public Shared Property EndNumber() As Integer
        Get
            Return _endNumber
        End Get
        Set(ByVal value As Integer)
            _endNumber = value
        End Set
    End Property
 
    Public Shared Function CountNumbers() As Boolean
 
        _currentNumber = _startNumber
 
        Dim progress As Integer = 0
 
        Do While _currentNumber <= _endNumber
            progress = CInt((_currentNumber / _endNumber) * 100)
            RaiseEvent CountProgress(progress)
            RaiseEvent CurrentCount(_currentNumber)
            _currentNumber += 1
            Threading.Thread.Sleep(100)
        Loop
 
    End Function
 
End Class

Open in new window

0
 
pdf-wbdAuthor Commented:
Carl - I had the logic correct, just for some reason the code changes I made were not taking hold. Once I created a separate project and compiled the dll with my code changes, it worked perfectly.
Thanks again for your help!!!
0
 
carlnorrbomCommented:
Hi,

Have you recompiled the dll and updated the dll reference to your frmExperts project? Sounds like it is not seeing the event coming in from the referenced class. Do a new build of the dll and remove / re-add the reference to the project.

/Carl.
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 4
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now