Results 1 to 9 of 9

Thread: [RESOLVED] BackGroundWorker freezing my app up

  1. #1
    Addicted Member
    Join Date
    Mar 12
    Posts
    177

    Resolved [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

  2. #2
    Addicted Member
    Join Date
    Mar 12
    Posts
    177

    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))

  3. #3
    .NUT jmcilhinney's Avatar
    Join Date
    May 05
    Location
    Sydney, Australia
    Posts
    80,872

    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.

  4. #4
    Addicted Member
    Join Date
    Mar 12
    Posts
    177

    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?

  5. #5
    .NUT jmcilhinney's Avatar
    Join Date
    May 05
    Location
    Sydney, Australia
    Posts
    80,872

    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.

  6. #6
    Loquacious User Shaggy Hiker's Avatar
    Join Date
    Aug 02
    Location
    Idaho
    Posts
    20,410

    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

  7. #7
    Addicted Member
    Join Date
    Mar 12
    Posts
    177

    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..

  8. #8
    .NUT jmcilhinney's Avatar
    Join Date
    May 05
    Location
    Sydney, Australia
    Posts
    80,872

    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.

  9. #9
    Addicted Member
    Join Date
    Mar 12
    Posts
    177

    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 02: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
  •