• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1299
  • Last Modified:

VB.net Backgroundworker while quering

I have a basic VB form that has a ListBox that is populated with the results from y WMI query of Programs.

The query takes longer than most of the WMI queries and my form is locked.
I know I can use BackgroundWorker Dowork, but I am not having any success with the collection results being passed into the Listbox and having a progress bar scroll while the process is doing work.

Imports System.Management
Imports System.DirectoryServices
Imports System.Net
Imports System.Net.OpenReadCompletedEventArgs
Imports System.Text
Imports System.Data
Imports System.ComponentModel

Public Class Form3
    Public Property ServerName() As String
        Get
            Return Me.Text
        End Get
        Set(ByVal Value As String)
            Me.Text = Value
        End Set
    End Property
    Private Sub Installed_Programs(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ' Label2.Text = [String].Empty
        BGWForm3.RunWorkerAsync()


    End Sub

    Private Sub Collect_Programs()
        Dim scope = New ManagementScope("\\" & Me.Text & "\root\cimv2")


        scope.Connect()

        Dim query As ObjectQuery
        query = New ObjectQuery("Select * from Win32_Product")
        Dim searcher As ManagementObjectSearcher
        searcher = New ManagementObjectSearcher(scope, query)
        Dim queryCollection As ManagementObjectCollection
        queryCollection = searcher.Get()

        Dim m As ManagementObject



        For Each m In queryCollection

            If m("name") Is Nothing Then
            Else

                ListBox1.Items.Add(m("name"))




            End If

        Next
    End Sub

    Private Sub BGWForm3_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BGWForm3.DoWork

        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        'Dim i As Integer


        If (worker.CancellationPending = True) Then
            e.Cancel = True
            'Exit For
        Else
            Collect_Programs()
            'Perform a time consuming operation and report progress.
            'System.Threading.Thread.Sleep(500)
            'worker.ReportProgress(i * 10)

        End If

    End Sub

    ' This event handler updates the progress. 
    'Private Sub backgroundWorker1_ProgressChanged(ByVal sender As System.Object, _
    'ByVal e As ProgressChangedEventArgs) Handles BGWForm3.ProgressChanged
    '    'resultLabel.Text = (e.ProgressPercentage.ToString() + "%")
    '    ToolStripProgressBar1.Value = e.ProgressPercentage
    'End Sub

    ' This event handler deals with the results of the background operation. 
    Private Sub backgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, _
    ByVal e As RunWorkerCompletedEventArgs) Handles BGWForm3.RunWorkerCompleted
        If e.Cancelled = True Then
            'resultLabel.Text = "Canceled!"
        ElseIf e.Error IsNot Nothing Then
            'resultLabel.Text = "Error: " & e.Error.Message
        Else
            'resultLabel.Text = "Done!"
            'ToolStripProgressBar1.Style.Blocks()
        End If
    End Sub



    Private Sub BGWForm3_ProgressChanged(ByVal sender As System.Object, ByVal e As ProgressChangedEventArgs) Handles BGWForm3.ProgressChanged
        'Me.ProgressBar1.Value = e.ProgressPercentage
        ToolStripProgressBar1.Style = ProgressBarStyle.Marquee
        ToolStripProgressBar1.MarqueeAnimationSpeed = 50
        ToolStripProgressBar1.Value = e.ProgressPercentage
        'ListBox1.Items.Add(e.)
    End Sub


End Class

Open in new window

0
yo_bee
Asked:
yo_bee
  • 6
  • 2
  • 2
  • +1
3 Solutions
 
käµfm³d 👽Commented:
The problem I think you are having--you didn't specify whether or not you were encountering errors--is that you are trying to update UI controls from separate threads. UI controls can only be updated from the thread on which they were created. In order to update across threads, you have to use the Invoke pattern. See my comment here:

http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_28305300.html#a39681287

...for a function that will let you interact with controls across threads. That example is for reading, but you can easily change it to writing instead. There is nothing special to do other than call the function.

The alternative, and probably more preferable way, would be to work with the ProgressChanged event.
0
 
yo_beeDirector of Information TechnologyAuthor Commented:
What if I just want the ProgressBar scroll Marque Style while the Query is running then when the query is complete the LISTBOX will be populated.

Is that possible without having a cross-thread?
0
 
käµfm³d 👽Commented:
A PB is still a UI control, so you will have the same issue.
0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

 
yo_beeDirector of Information TechnologyAuthor Commented:
Here is the errorCross-thread
0
 
CodeCruiserCommented:
One way to accomplish this would be to declare queryCollection at class level. Then move the following code

        For Each m In queryCollection

            If m("name") Is Nothing Then
            Else

                ListBox1.Items.Add(m("name"))




            End If

        Next

Open in new window



out of Collect_Programs method and into backgroundWorker1_RunWorkerCompleted method.
0
 
yo_beeDirector of Information TechnologyAuthor Commented:
Sorry, but I am a novice when it comes to some of these methods and what your saying I am not sure how to do.
0
 
CodeCruiserCommented:
I pointed out the steps but here those are again

1) Move
Dim queryCollection As ManagementObjectCollection

line out of Collect_Programs to just under your

Public Class Form3

line.

2) Move the code shown above out of the Collect_Programs and into RunWorkerCompleted method.
0
 
yo_beeDirector of Information TechnologyAuthor Commented:
@CodeCrusier

Thanks for the suggestion.
It partially worked.
The form still is locked up during the process.

What I would like is to either have a progressbar scroll while the data is being collected and once complete populate the Listview (I made a change from ListBox to a ListView)
0
 
ArkCommented:
You can fill ListBox in BGWForm3_ProgressChanged event handler. Use UserState property to pass name:
    Private Sub Collect_Programs(ByVal worker As BackgroundWorker)
'skipped
        Dim i, count, percents As Integer
        count = queryCollection.Count
        For Each m In queryCollection
            i+=1
            If m("name") Is Nothing Then
            Else
                percents = i*100/count
                worker.ReportProgress(i, m("name"))
            End If

        Next
    End Sub

    Private Sub BGWForm3_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BGWForm3.DoWork

        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        If (worker.CancellationPending = True) Then
            e.Cancel = True
        Else
            Collect_Programs(worker)
        End If

    End Sub

    Private Sub BGWForm3_ProgressChanged(ByVal sender As System.Object, ByVal e As ProgressChangedEventArgs) Handles BGWForm3.ProgressChanged
        ToolStripProgressBar1.Value = e.ProgressPercentage
        ListBox1.Items.Add(e.UserState.ToString)
    End Sub

Open in new window

0
 
yo_beeDirector of Information TechnologyAuthor Commented:
What if I changed the Listbox1 to ListView1 and the Listview has two columns?

        For Each m In queryCollection

            If m("name") Is Nothing Then
            Else

                Dim LVI As New ListViewItem
                LVI.Text = m("name")
                LVI.SubItems.Add(m("Version"))
                ' bw.ReportProgress(i)

                ListView1.Items.Add(LVI)
                ListView1.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.ColumnContent)
                ListView1.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent)
                ''ListBox1.Items.Add(m("name"))

            End If

        Next

Open in new window

0
 
ArkCommented:
You can't call UI items (form controls) from another thread. But you can post any object accross threads via ReportProgress:
   For Each m In queryCollection

            If m("name") Is Nothing Then
            Else
                bw.ReportProgress(i, m)
            End If

        Next
   Private Sub BGWForm3_ProgressChanged(ByVal sender As System.Object, ByVal e As ProgressChangedEventArgs) Handles BGWForm3.ProgressChanged
        ToolStripProgressBar1.Value = e.ProgressPercentage
        Dim m = e.UserState
        Dim LVI As New ListViewItem
        LVI.Text = m("name")
        LVI.SubItems.Add(m("Version"))
        ListView1.Items.Add(LVI)
        ListView1.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.ColumnContent)
        ListView1.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent)
  End Sub

Open in new window

0
 
yo_beeDirector of Information TechnologyAuthor Commented:
I want to thank everyone for their suggestions.
This one is a tough one for me to wrap my head around.
I tried to follow http://www.codeproject.com/Articles/93260/Retrieving-Information-From-Windows-Management-Ins, but I had trouble understanding the Delegates .

Thanks
ARK.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

  • 6
  • 2
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now