Question BackGroundWorker Question(s)

inkedgfx

Well-known member
Joined
Sep 29, 2012
Messages
139
Location
USA
Programming Experience
Beginner
I added a backgroundworker to my lottery number generator program..everything is working fine but the backgroundworker keeps working even if all the games are picked....

for example:

the user has the option to choose from 1 to 6 games to generate...each game generates 6 unique numbers...once the worker picks the numbers the labels display the numbers for each game...this works fine , once all the labels are filled with the numbers the worker continues to pick numbers and changes the labels with different numbers.....below is the code I have for the worker.....

 Private Sub BackgroundWorker1_DoWork(sender As Object, e As ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim HowMany As Integer
        frmNumbers.Show()
        HowMany = Me.NumericUpDown1.Value
        frmNumbers.Label1.Visible = False
        frmNumbers.Label2.Visible = False
        frmNumbers.Label3.Visible = False
        frmNumbers.Label4.Visible = False
        frmNumbers.Label5.Visible = False
        frmNumbers.Label6.Visible = False

        If HowMany = "1" Then
            frmNumbers.Label1.Visible = True
            frmNumbers.Label11.Text = HowMany & " Game Generated!"
            frmNumbers.Text = HowMany & " Game Generated!"
            RandomUnique(frmNumbers.Label1)
 
            frmNumbers.Label1.Text = frmNumbers.Label1.Text.Substring(0, frmNumbers.Label1.Text.Length - 2)

        End If
        If HowMany = "2" Then
            frmNumbers.Label1.Visible = True
            frmNumbers.Label2.Visible = True
            frmNumbers.Label11.Text = HowMany & " Games Generated!"
            frmNumbers.Text = HowMany & " Games Generated!"
            RandomUnique(frmNumbers.Label1)
            frmNumbers.Label1.Text = frmNumbers.Label1.Text.Substring(0, frmNumbers.Label1.Text.Length - 2)

            ' RandomUniqueTwo(Label2)
            ' Label2.Text = Label2.Text.Substring(0, Label2.Text.Length - 2)
            Do Until frmNumbers.Label2.Text < frmNumbers.Label1.Text
                RandomUniqueTwo(frmNumbers.Label2)
                frmNumbers.Label2.Text = frmNumbers.Label2.Text.Substring(0, frmNumbers.Label2.Text.Length - 2)
            Loop
        End If
        If HowMany = "3" Then
            frmNumbers.Label1.Visible = True
            frmNumbers.Label2.Visible = True
            frmNumbers.Label3.Visible = True
            frmNumbers.Label11.Text = HowMany & " Games Generated"
            frmNumbers.Text = HowMany & " Games Generated!"
            RandomUnique(frmNumbers.Label1)
            frmNumbers.Label1.Text = frmNumbers.Label1.Text.Substring(0, frmNumbers.Label1.Text.Length - 2)
            Do Until frmNumbers.Label2.Text < frmNumbers.Label1.Text
                RandomUniqueTwo(frmNumbers.Label2)
                frmNumbers.Label2.Text = frmNumbers.Label2.Text.Substring(0, frmNumbers.Label2.Text.Length - 2)
            Loop
            Do Until frmNumbers.Label3.Text < frmNumbers.Label2.Text
                RandomUnique(frmNumbers.Label3)
                frmNumbers.Label3.Text = frmNumbers.Label3.Text.Substring(0, frmNumbers.Label3.Text.Length - 2)
            Loop
            Application.DoEvents()
        End If

        If HowMany = "4" Then
            frmNumbers.Label1.Visible = True
            frmNumbers.Label2.Visible = True
            frmNumbers.Label3.Visible = True
            frmNumbers.Label4.Visible = True
            frmNumbers.Label11.Text = HowMany & " Games Generated"
            frmNumbers.Text = HowMany & " Games Generated!"
            RandomUnique(frmNumbers.Label1)
            frmNumbers.Label1.Text = frmNumbers.Label1.Text.Substring(0, frmNumbers.Label1.Text.Length - 2)
            Do Until frmNumbers.Label2.Text < frmNumbers.Label1.Text
                RandomUniqueTwo(frmNumbers.Label2)
                frmNumbers.Label2.Text = frmNumbers.Label2.Text.Substring(0, frmNumbers.Label2.Text.Length - 2)
            Loop
            Do Until frmNumbers.Label3.Text < frmNumbers.Label2.Text
                RandomUnique(frmNumbers.Label3)
                frmNumbers.Label3.Text = frmNumbers.Label3.Text.Substring(0, frmNumbers.Label3.Text.Length - 2)
            Loop
            Do Until frmNumbers.Label4.Text < frmNumbers.Label3.Text
                RandomUnique(frmNumbers.Label4)
                frmNumbers.Label4.Text = frmNumbers.Label4.Text.Substring(0, frmNumbers.Label4.Text.Length - 2)
            Loop
            Application.DoEvents()
        End If
        If HowMany = "5" Then
            frmNumbers.Label1.Visible = True
            frmNumbers.Label2.Visible = True
            frmNumbers.Label3.Visible = True
            frmNumbers.Label4.Visible = True
            frmNumbers.Label5.Visible = True
            frmNumbers.Label11.Text = HowMany & " Games Generated"
            frmNumbers.Text = HowMany & " Games Generated!"
            RandomUnique(frmNumbers.Label1)
            frmNumbers.Label1.Text = frmNumbers.Label1.Text.Substring(0, frmNumbers.Label1.Text.Length - 2)
            Do Until frmNumbers.Label2.Text < frmNumbers.Label1.Text
                RandomUniqueTwo(frmNumbers.Label2)
                frmNumbers.Label2.Text = frmNumbers.Label2.Text.Substring(0, frmNumbers.Label2.Text.Length - 2)
            Loop
            Do Until frmNumbers.Label3.Text < frmNumbers.Label2.Text
                RandomUnique(frmNumbers.Label3)
                frmNumbers.Label3.Text = frmNumbers.Label3.Text.Substring(0, frmNumbers.Label3.Text.Length - 2)
            Loop
            Do Until frmNumbers.Label4.Text < frmNumbers.Label3.Text
                RandomUnique(frmNumbers.Label4)
                frmNumbers.Label4.Text = frmNumbers.Label4.Text.Substring(0, frmNumbers.Label4.Text.Length - 2)
            Loop
            Do Until frmNumbers.Label5.Text < frmNumbers.Label4.Text
                RandomUnique(frmNumbers.Label5)
                frmNumbers.Label5.Text = frmNumbers.Label5.Text.Substring(0, frmNumbers.Label5.Text.Length - 2)
            Loop
            Application.DoEvents()
        End If
        For i As Integer = 1 To HowMany - 1
            If HowMany = "6" Then
                frmNumbers.Label1.Visible = True
                frmNumbers.Label2.Visible = True
                frmNumbers.Label3.Visible = True
                frmNumbers.Label4.Visible = True
                frmNumbers.Label5.Visible = True
                frmNumbers.Label6.Visible = True
                frmNumbers.Label11.Text = HowMany & " Games Generated"
                frmNumbers.Text = HowMany & " Games Generated!"
                RandomUnique(frmNumbers.Label1)
                frmNumbers.Label1.Text = frmNumbers.Label1.Text.Substring(0, frmNumbers.Label1.Text.Length - 2)
                Do Until frmNumbers.Label2.Text < frmNumbers.Label1.Text
                    RandomUniqueTwo(frmNumbers.Label2)
                    frmNumbers.Label2.Text = frmNumbers.Label2.Text.Substring(0, frmNumbers.Label2.Text.Length - 2)
                Loop
                Application.DoEvents()
                Do Until frmNumbers.Label3.Text < frmNumbers.Label2.Text
                    RandomUnique(frmNumbers.Label3)
                    frmNumbers.Label3.Text = frmNumbers.Label3.Text.Substring(0, frmNumbers.Label3.Text.Length - 2)
                Loop
                Application.DoEvents()
                Do Until frmNumbers.Label4.Text < frmNumbers.Label3.Text
                    RandomUnique(frmNumbers.Label4)
                    frmNumbers.Label4.Text = frmNumbers.Label4.Text.Substring(0, frmNumbers.Label4.Text.Length - 2)
                Loop
                Application.DoEvents()
                Do Until frmNumbers.Label5.Text < frmNumbers.Label4.Text
                    RandomUnique(frmNumbers.Label5)
                    frmNumbers.Label5.Text = frmNumbers.Label5.Text.Substring(0, frmNumbers.Label5.Text.Length - 2)
                Loop
                Application.DoEvents()
                Do Until frmNumbers.Label6.Text < frmNumbers.Label5.Text
                    RandomUnique(frmNumbers.Label6)
                    frmNumbers.Label6.Text = frmNumbers.Label6.Text.Substring(0, frmNumbers.Label6.Text.Length - 2)
                Loop
                Application.DoEvents()
                BackgroundWorker1.ReportProgress(i)
            End If
        Next
    End Sub
    Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        frmNumbers.ProgressBar1.Value = e.ProgressPercentage
        frmNumbers.lblPercentDone.Text = frmNumbers.lblPercentDone.Text & " %"
    End Sub
    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        Dim HowMany As Integer
        HowMany = Me.NumericUpDown1.Value
        frmNumbers.ProgressBar1.Value = 0
        frmNumbers.lblgenerating.Text = HowMany & " Games Generated"
    End Sub


what I want the worker to do is stop when all the games are picked.the last bit of the backgroundworker_dowork I added a for loop to calculate the progress..which doesnt work either.

any help would be appreciated

Thank You
InkedGFX
 
The first thing you should do is get rid of all that code. The whole point of a BackgroundWorker is to do background work but everything you're doing deals with the UI, so pretty much none of it is background work. A BackgroundWorker in this case is completely pointless. The only actual background work you could do would be generating the numbers, which would actually take milliseconds. That code is, I'm afraid, really, really terrible. I'm not trying to have a go at you. I've written terrible code myself in the past but that code really is terrible. Why are you using a BackgroundWorker at all in the first place?
 
the only reason I thought about using a background worker is because when the user generates 4 or more games of numbers ..the program lags until all the numbers are picked...this takes different amounts of time....one time it will be quite fast but the next it will take upto 2 minutes or so.....so I read online that a backgroundworker would do this work in the background and the program wouldnt "freeze" until the operation was complete...

would you have any suggestions on optimizing this code?
I know its terrible code...Im still learning this.

InkedGFX
 
I'm guessing that the issue with the time taken is because of the way you're generating the random numbers. I bet you're picking a number at random and then checking whether it's one of the numbers you've already picked and discarding it if it is and trying again, right? If you do that then, theoretically, you might take an infinite amount of time to come up with the desired number of choices. The way to do it is to avoid duplicates in the first place. Try running this code:
Private rng As New Random

Private Sub GetLotteryNumbers()
    Dim watch = Stopwatch.StartNew()

    'There are 40 possible lottery numbers.
    Dim allNumbers = Enumerable.Range(1, 40).ToArray()

    Dim gameNumbers As New List(Of Integer())

    'Get 10 games of 6 numbers each.
    For i = 1 To 10
        gameNumbers.Add(GetRandomSelections(allNumbers, 6))
    Next

    MessageBox.Show(String.Format("It took {0} milliseconds to generate 10 games of 6 numbers.", watch.ElapsedMilliseconds))

    For i = 1 To 10
        MessageBox.Show(String.Join(", ", gameNumbers(i - 1)), "Game " & i)
    Next
End Sub

''' <summary>
''' Gets a number of unique random items from a list.
''' </summary>
''' <typeparam name="T">
''' The type of the items in the list.
''' </typeparam>
''' <param name="list">
''' The list to select the items from.
''' </param>
''' <param name="count">
''' the number of items to select.
''' </param>
''' <returns>
''' An array containing the selected items.
''' </returns>
Private Function GetRandomSelections(Of T)(list As IEnumerable(Of T), count As Integer) As T()
    'The OrderBy call randomises the list and the Take call
    'gets the appropriate number of items from the beginning.
    Return list.OrderBy(Function(item) rng.NextDouble()).Take(count).ToArray()
End Function
That will show you just how fast it should be to generate random selections like this. In my testing, the slowest was 116 ms, i.e. just over 1/10 of a second, and the fastest was 10 ms, i.e. 1/100 of a second. No need to do that in a secondary thread.
 
wow...very cool....

I knew I was generating the number the long way.....thank you for the help...

InkedGFX
 
I'm getting a few errors with the code

   Private Sub GenerateLotteryNumbers()
        Dim watch = Stopwatch.StartNew()
        ' there are 53 possible lottery numbers
        Dim allNumbers = Enumerable.Range(1, 53).ToArray() <---- Enumerable isnt declared and may be innaccessable
        'set new List to store the game numbers
        Dim gameNumbers As New List(Of Integer())
        ' generate 10 games of 6 numbers each
        For i As Integer = 1 To 10
            gameNumbers.add(GetRandomSelection(allNumbers, 6))
        Next
        messagebox.show(String.format("It took {0} milliseconds to generate 10 games of 6 numbers.", watch, ElapsedMilliseconds))<---- same here , ElapsedMilliseconds not declared
        For i As Integer = 1 To 10
            messagebox.show(String.join(", ", gameNumbers(i - 1)), "Game " & i) <----- value of type 1-dimensional array of integer cannot be converted to 1 dimentional array of string because Integer is not derived from string
        Next
    End Sub

Private Function GetRandomSelection(Of T)(list As IEnumerable(Of T), count As Integer) As T()
        Return list.OrderBy(Function(item) rng.NextDouble()).Take(count).ToArray() <---- orderBy is not a member of System.Collections.Generic>IEnumarable(Of T)
    End Function


are there some Imports that I am missing ...I have

Imports System
Imports System.Threading
Imports System.IO
Imports System.Text
Imports System.Collections.Generic
Imports System.Collections.ArrayList


thank you for the help....

InkedGFX
 
one other question.. I cannot import System.Linq ?

Im using VS 2012...is this a known issue?

InkedGFX
 
ok..I figured out my problem with not being able to import System.Linq
I needed to change the framework I was using....I switched to the 3.5 framework and fixed 2 errors.......

gameNumbers(i - 1)) still giving me error...

InkedGFX
 
Jmcilhinney : I took your code and tried to get it to fill a label with just 6 numbers....this returns something unexpected.

  Dim allNumbers = Enumerable.Range(1, 53).ToArray()
        Dim gameNumbers As New List(Of Integer())
        gameNumbers.Add(GetRandomSelection(allNumbers, 6))
        lblNumbers.Text = String.Join(", ", gameNumbers)


the label is filled with "System.Int32[]" , not 6 numbers as I expected...any idea why this would happen?

InkedGFX
 
nevermind....I had it wrong...thank you for the help...this will speed my program emensley...thanks again......below is the code that works

Dim allNumbers As IEnumerable(Of Integer) = Enumerable.Range(1, 53).ToArray()
        Dim myNumbers As String
        Dim gameNumbers As New List(Of Integer())
        For i = 1 To 10
            gameNumbers.Add(GetRandomSelection(allNumbers, 6))
        Next
        For i = 1 To 6
            myNumbers = String.Join(", ", gameNumbers(i - 1))
            lblNumbers.Text = myNumbers
        Next


InkedGFX
 
WOW!

I didnt realize how inefficient my code was until you showed me the correct way to do this...man , I have alot to learn

thanks again

InkedGFX
 
nevermind....I had it wrong...thank you for the help...this will speed my program emensley...thanks again......below is the code that works

Dim allNumbers As IEnumerable(Of Integer) = Enumerable.Range(1, 53).ToArray()
        Dim myNumbers As String
        Dim gameNumbers As New List(Of Integer())
        For i = 1 To 10
            gameNumbers.Add(GetRandomSelection(allNumbers, 6))
        Next
        For i = 1 To 6
            myNumbers = String.Join(", ", gameNumbers(i - 1))
            lblNumbers.Text = myNumbers
        Next


InkedGFX

Do you realise that that code is generating 10 sets of 6 numbers and then and then only using 6 of those sets?
 
you know I thought that looked funny....but the code worked so I didnt change it......I need it to generate up to 10 games...with 6 numbers in each game... then fill 10 labels with the 10 games generated...if that makes sence....

InkedGFX
 
Back
Top