|
-
Mar 8th, 2012, 03:06 AM
#1
Thread Starter
Hyperactive Member
[RESOLVED] BackGroundWorker freezing my app up
Hey Everyone,
I was messing around with the listview Control first,, And when i got it working i thought what's this backgroundworker thing,,so i read up on what info MS had on the MSDN page..and slapped it in here..and i thought i had it working ok until i tried to move my project application to the side to reply to a instant message i got..and then i noticed that it froze up .
and looked like it was using alot of system resources,
But wait let me back up just a bit.originally i was trying it with a fairly small number of items, and then i seen on here where someone had posted a rather large index for testing his app with,,and while trying to load that list that's when the issue was noticed 
i don't really plan on loading a list as big as that test index was but, I would still like to know why the program did what it did using the code below.
I'm not really asking for it to be too altered, i kinda like all the controls i have in it the moment,, and the way it loaded as well. but if someone could point me to the reason the app froze i would really appreciate it.
Thanks in Advance 
Code:
Imports System.IO
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Threading
Imports System.Collections
Imports System
Public Class Form1
Inherits Form
Private inhibitAutoCheck As Boolean
Dim listView1 As New ListView()
Dim Counter As Long, Total_Items As Long, File_Path As String, String_Array() As String
Private Delegate Sub Start_LoadingDelegate(ByVal parameter As Array)
Private Delegate Sub Begin_UpdateDelegate()
Dim Item As ListViewItem
Public Sub New()
InitializeComponent()
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.WorkerReportsProgress = True
End Sub
Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim bw As BackgroundWorker = CType(sender, BackgroundWorker)
TimeConsumingOperation(bw)
End Sub
Private Function TimeConsumingOperation(ByVal bw As BackgroundWorker) As Integer
Dim [exit] As Boolean = False
Dim Input_String() As String = IO.File.ReadAllLines(File_Path)
Total_Items = Input_String.GetUpperBound(0)
Begin_Update()
Try
For Me.Counter = 1 To Total_Items - 1
Dim String_Array() As String = Split(Input_String(Me.Counter), ",")
Start_Loading(String_Array)
BackgroundWorker1.ReportProgress(Counter * 100 / Total_Items)
If [exit] Then
Exit For
End If
Next
Catch
MsgBox("Problemo")
End Try
End Function
Public Sub Begin_Update()
If Not InvokeRequired Then
listView1.BeginUpdate()
Else
Invoke(New Begin_UpdateDelegate(AddressOf Begin_Update), New Object() {})
End If
End Sub
Public Sub Start_Loading(ByVal String_Array As Array)
If Not InvokeRequired Then
Item = listView1.Items.Add(String_Array(0))
Item.SubItems.Add(String_Array(1))
Item.SubItems.Add(String_Array(2))
Item.SubItems.Add(String_Array(3))
Item.SubItems.Add(String_Array(4))
Item.SubItems.Add(String_Array(5))
Item.SubItems.Add(String_Array(6))
Item.SubItems.Add(String_Array(7))
Item.SubItems.Add(String_Array(8))
Item.SubItems.Add(String_Array(9))
Else
Invoke(New Start_LoadingDelegate(AddressOf Start_Loading), New Object() {String_Array})
End If
End Sub
Private Sub backgroundWorker1_ProgressChanged(ByVal sender As Object, _
ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
resultLabel.Text = (e.ProgressPercentage.ToString() + "%")
End Sub
Private Sub backgroundWorker1_RunWorkerCompleted(ByVal sender As Object, _
ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Cancelled Then
resultLabel.Text = "Canceled!"
ElseIf (e.Error IsNot Nothing) Then
resultLabel.Text = "Error: " & e.Error.Message
Else
resultLabel.Text = "Done!"
listView1.EndUpdate()
End If
End Sub
Private Sub startButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles startBtn.Click
Dim openFileDialog1 As New OpenFileDialog()
openFileDialog1.InitialDirectory = "D:\"
openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"
openFileDialog1.FilterIndex = 1
If openFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
File_Path = openFileDialog1.FileName
Me.BackgroundWorker1.RunWorkerAsync()
End If
End Sub
Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cancelBtn.Click
Me.BackgroundWorker1.CancelAsync()
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Me.listView1.Bounds = New Rectangle(New Point(12, 12), New Size(938, 418))
Me.listView1.Columns.Add("Column1", 200, HorizontalAlignment.Left)
Me.listView1.Columns.Add("Column2", 250, HorizontalAlignment.Left)
Me.listView1.Columns.Add("Column3", 100, HorizontalAlignment.Left)
Me.listView1.Columns.Add("Column4", 120, HorizontalAlignment.Left)
Me.listView1.Columns.Add("Column5", 100, HorizontalAlignment.Right)
Me.listView1.Columns.Add("Column6", 100, HorizontalAlignment.Left)
Me.listView1.Columns.Add("Column7", 120, HorizontalAlignment.Left)
listView1.View = View.Details
listView1.LabelEdit = False
listView1.AllowColumnReorder = True
listView1.CheckBoxes = True
listView1.Anchor = AnchorStyles.Top Or AnchorStyles.Left Or AnchorStyles.Bottom Or AnchorStyles.Right
Me.Controls.Add(listView1)
End Sub
End Class
-
Mar 8th, 2012, 03:34 AM
#2
Thread Starter
Hyperactive Member
Re: BackGroundWorker freezing my app up
oh there it is,i guess this first post did make it thru..there's another one too you can ignore it. it' the same as this one
there's too many items in the above code so you'll need to remove the
Code:
Item.SubItems.Add(String_Array(7))
Item.SubItems.Add(String_Array(8))
Item.SubItems.Add(String_Array(9))
-
Mar 8th, 2012, 03:59 AM
#3
Re: BackGroundWorker freezing my app up
I don;t think that you've grasped exactly what the BackgroundWorker is for. It's for doing background work. Loading items into a ListView is NOT background work. It is the very definition of foreground work, i.e. updating the UI. Getting the data to load into the ListView can be background work. Creating the ListViewItems containing the data acn even be background work. Adding the items the ListView is NOT background work.
There are three reasonable ways to go about loading a ListView with the aid of a BackgroundWorker:
1. Get the data in the DoWork event handler and create the ListViewItem there, then call ReportProgress and add the ListViewItem to the ListView in the ProgressChanged event handler. You would only do it this way if there is a reasonable gap between the addition of each item because if you're going back to the UI thread over and over in quick succession then you get little to no benefit from the multi-threading.
2. The same as option 1 but wait for a while between ReportProgress calls and add the items in batches, e.g. 10 items at a time. You might do this in the situation I mentioned that option 1 is inappropriate. Using batches creates a larger break between ReportProgress calls and therefore increases overall performance.
3. Don't call ReportProgress at all. Create all the ListViewItems and then add them to the ListView in one batch in the RunWorkerCompleted event handler.
Follow the CodeBank link in my signature and check out my thread on Using The BackgroundWorker. You'll find examples of options 1 and 3 and, if you want to use option 2, you should be able to work that out for yourself by modifying code for option 1.
-
Mar 8th, 2012, 05:48 AM
#4
Thread Starter
Hyperactive Member
Re: BackGroundWorker freezing my app up
ok
So a BackGroundWorker wouldn't be the optimum choice for what i tried to use it for..gotcha 
If i take out the backgroundworker, what would be a suitable way to load the listview without locking the Application up while it's loading the info into the listview?
-
Mar 8th, 2012, 06:22 AM
#5
Re: BackGroundWorker freezing my app up
It's not possible to have the UI thread do anything else while it's loading items into the ListView. As I said, you can use a BackgroundWorker to retrieve the data and create the items and do the absolute minimum amount of work, i.e. add the items to the ListView, on the UI thread. While those items are being added though, the application simply cannot do anything else.
-
Mar 8th, 2012, 01:35 PM
#6
Re: BackGroundWorker freezing my app up
If you are loading the items in a loop, then you could add an Application.DoEvents line into the loop. What you see as 'locking up' isn't really locking up, it is just that the UI is so busy that it can't take the time to respond to any messages. You might be clicking the mouse on this thing or that thing, but all that will be doing will be queueing up messages about the mouse clicking. The app is busy, so it isn't getting those messages off the queue. DoEvents tells the app to process any pending messages, so the app will be responsive, but that will come at a cost. Calling DoEvents each time through the loop will make the form responsive, but will mean that the loop will take several times as long to complete, most likely.
There is one other consideration if you use DoEvents, too. The form WILL be responsive. It will respond to any user actions even as the list is filling. Is there anything that the user might do that would be bad to do with a partially filled list? If so, you would certainly want to prevent that.
My usual boring signature: Nothing
 
-
Mar 8th, 2012, 06:36 PM
#7
Thread Starter
Hyperactive Member
Re: BackGroundWorker freezing my app up
ok, I tried jmcilhinney suggestion first that kept adding the same lines multiple times, and the other option wouldn't go past the "Item = listView1.Items.Add(String_Array(0))"
I then went back to the original code and tried Saggy Hikers suggestion and added a application.doevents just before the "If Not InvokeRequired Then
" in that same sub and it's responding just fine now..i can move it to the side, minimize it, maximize it..etc. and the loading keeps right on going.
So now that that's working, what can be done to speed it up? without leaving a blank area in the app. where the listview is at start up..I see alot of ppl waiting until the very end to post the listview up on the form..
-
Mar 8th, 2012, 06:51 PM
#8
Re: BackGroundWorker freezing my app up
In actual fact, using Application.DoEvents will be slowing the whole process down. The best option is to load all the data and create all the ListViewItems in the background, i.e. in the DoWork event handler, and then add all the items in one go using AddRange when you're done, i.e. in the RunWorkerCompleted event handler.
-
Mar 9th, 2012, 04:14 AM
#9
Thread Starter
Hyperactive Member
Re: BackGroundWorker freezing my app up
hmm, I looked over your Code bank Material, But i couldn't quit grasp what you were trying to tell me,,I want to understand it , I really do,i even went looking for keywords based on your typing, and i found a few things that looked like they might have been what you talking about, but when i tried to put the stuff in this project , it didn't work out good 
I did find one thing that interested me tho on your thread page..the BeginEnvoke i noticed that when i changed the line highlighted in red.
the loading was 50 % faster..however it didn't like the application.doevents at all.
If i could keep the BeginEnvoke in there and still keep the program so it can be moved on the desktop,then that would be great.
i also made a few other changes to the previous code as well, based on what i found in the code bank .
If the above isn't possible then:
If you Could Friend I'd really like an example code that shows exactly what you were trying to get me to do.
Code:
Private Function TimeConsumingOperation(ByVal bw As BackgroundWorker) As Integer
Dim [exit] As Boolean = False
Begin_Update()
Try
Dim Input_String() As String = IO.File.ReadAllLines(File_Path)
Total_Items = Input_String.GetUpperBound(0)
For Me.Counter = 1 To Total_Items - 1
Application.DoEvents()
Dim String_Array() As String = Split(Input_String(Me.Counter), ",")
Start_Loading(String_Array)
bw.ReportProgress(Me.Counter * 100 / Total_Items)
If [exit] Then
Exit For
End If
Next
Catch
MsgBox("Problemo")
End Try
End Function
Public Sub Start_Loading(ByVal String_Array As Array)
If Not InvokeRequired Then
Me.listView1.Items.Add(New ListViewItem(String_Array))
Else
Invoke(New Start_LoadingDelegate(AddressOf Start_Loading), New Object() {String_Array})
End If
End Sub
Private Sub bw(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
resultLabel.Text = (e.ProgressPercentage.ToString() + "%")
End Sub
Last edited by M@dH@tter; Mar 9th, 2012 at 03:10 PM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|