Solved

vb.net and using a background worker

Posted on 2014-11-06
3
439 Views
Last Modified: 2014-11-06
I developed a program that uses WMI to retrieve processes running on a remote workstation.  The problem is it takes about 15 seconds to fully load everything.  My solution is running that method in a background thread so that the user GUI isnt completely frozen making it look like my app is broke.  I am using the below code to run this in the background worker.  ( The example i am using from http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx works fine).  I get an error with the below code (Cross-thread operation not valid: Control 'ListView1' accessed from a thread other than the thread it was created on.)

Imports System.ComponentModel
Imports System.Management

Public Class Form1
    Private bw As BackgroundWorker = New BackgroundWorker


    Public Sub New()
        InitializeComponent()
        bw.WorkerReportsProgress = True
        bw.WorkerSupportsCancellation = True
        AddHandler bw.DoWork, AddressOf BackgroundWorker1_DoWork
        AddHandler bw.ProgressChanged, AddressOf BackgroundWorker1_ProgressChanged
        AddHandler bw.RunWorkerCompleted, AddressOf BackgroundWorker1_RunWorkerCompleted

    End Sub


    Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        'For i = 1 To 10
        'If bw.CancellationPending = True Then
        '    e.Cancel = True
        '    Exit For
        'Else
        ' Perform a time consuming operation and report progress.
        'System.Threading.Thread.Sleep(500)
        'bw.ReportProgress(i * 10)
        Dim RC As String = "10.243.12.139"
        
            ListView1.Items.Clear()

            Dim theScope As New ManagementScope("\\" & RC & "\root\cimv2")
            Dim objectQuery As New ObjectQuery("SELECT * FROM Win32_Process")
            ListView1.Groups.Add(New ListViewGroup("Processes", "Process List"))
            For Each managementObject As ManagementObject In (New ManagementObjectSearcher(theScope, objectQuery)).[Get]()
                Dim item As ListViewItem = ListView1.Items.Add(managementObject("Name").ToString())
                item.SubItems.Add(managementObject("ProcessId").ToString())
                item.Group = ListView1.Groups("Processes")
            Next
                'End If
        'Next

    End Sub

    Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        Me.tbProgress.Text = e.ProgressPercentage.ToString() & "%"

    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        If e.Cancelled = True Then
            Me.tbProgress.Text = "Canceled!"
        ElseIf e.Error IsNot Nothing Then
            Me.tbProgress.Text = "Error: " & e.Error.Message
        Else
            Me.tbProgress.Text = "Done!"
        End If

    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If Not bw.IsBusy = True Then
            bw.RunWorkerAsync()
        End If

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        If bw.WorkerSupportsCancellation = True Then
            bw.CancelAsync()
        End If
    End Sub
End Class

Open in new window

0
Comment
Question by:derek7467
3 Comments
 
LVL 142

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 40425970
I had the same issue. problem is indeed that the background worker process will not have access to any of the visual controls (by that error message)
the solution I had implemented is that the background worker process fills the data into some variable of the form (for example some collection...), and when done (in the event) requests the form to refresh from that collection.
0
 
LVL 32

Accepted Solution

by:
it_saige earned 500 total points
ID: 40426317
Actually there is a really simple solution to this issue.  Use the background workers report progress to update the listview.
Imports System.ComponentModel
Imports System.Linq
Imports System.Management

Public Class Form1
	Private bw As BackgroundWorker = New BackgroundWorker

	Public Sub New()
		InitializeComponent()
		bw.WorkerReportsProgress = True
		bw.WorkerSupportsCancellation = True
		AddHandler bw.DoWork, AddressOf OnDoWork
		AddHandler bw.ProgressChanged, AddressOf OnProgressChanged
		AddHandler bw.RunWorkerCompleted, AddressOf OnWorkerCompleted
	End Sub

	Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
		If Not bw.IsBusy = True Then
			ListView1.Items.Clear()
			ListView1.Groups.Add(New ListViewGroup("Processes", "Process List"))
			ListView1.Groups.Add(New ListViewGroup("Sandwiches", "Sandwich List"))
			bw.RunWorkerAsync()
		End If
	End Sub

	Private Sub OnDoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
		Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
		Dim RC As String = "10.243.12.139"

		Dim theScope As New ManagementScope(String.Format("\\{0}\root\cimv2", RC))
		Dim objectQuery As New ObjectQuery("SELECT * FROM Win32_Process")
		For Each managementObject As ManagementObject In (New ManagementObjectSearcher(theScope, objectQuery)).[Get]()
			Dim item As New ListViewItem(managementObject("Name").ToString())
			item.SubItems.Add(managementObject("ProcessId").ToString())
			worker.ReportProgress(0, New ListViewState() With {.Item = item, .Group = ListViewGroupDefinition.Processes})
		Next
		worker.ReportProgress(0, New ListViewState() With {.Item = New ListViewItem("Ham"), .Group = ListViewGroupDefinition.Sandwiches})
		worker.ReportProgress(0, New ListViewState() With {.Item = New ListViewItem("Salami"), .Group = ListViewGroupDefinition.Sandwiches})
		worker.ReportProgress(0, New ListViewState() With {.Item = New ListViewItem("Turkey"), .Group = ListViewGroupDefinition.Sandwiches})
		'End If
		'Next

	End Sub

	Private Sub OnProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
		Me.tbProgress.Text = e.ProgressPercentage.ToString() & "%"
		If Not e.UserState Is Nothing AndAlso TypeOf e.UserState Is ListViewState Then
			Dim state As ListViewState = TryCast(e.UserState, ListViewState)
			If Not state Is Nothing Then
				Select Case state.Group
					Case ListViewGroupDefinition.None
						Exit Select
					Case ListViewGroupDefinition.Processes
						state.Item.Group = ListView1.Groups("Processes")
						Exit Select
					Case ListViewGroupDefinition.Sandwiches
						state.Item.Group = ListView1.Groups("Sandwiches")
						Exit Select
				End Select
				ListView1.Items.Add(state.Item)
			End If
		End If
	End Sub

	Private Sub OnWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
		If e.Cancelled = True Then
			Me.tbProgress.Text = "Canceled!"
		ElseIf e.Error IsNot Nothing Then
			Me.tbProgress.Text = "Error: " & e.Error.Message
		Else
			Me.tbProgress.Text = "Done!"
		End If
	End Sub
End Class

Public Class ListViewState
	Public Property Item() As ListViewItem
	Public Property Group As ListViewGroupDefinition
End Class

Public Enum ListViewGroupDefinition As Integer
	None = 0
	Processes = 1
	Sandwiches = 2
End Enum

Open in new window


-saige-
0
 

Author Closing Comment

by:derek7467
ID: 40426516
AWESOME!!!!!! Thank you!
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

This article describes relatively difficult and non-obvious issues that are likely to arise when creating COM class in Visual Studio and deploying it by professional MSI-authoring tools. It is assumed that the reader is already familiar with the cla…
Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now