Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub

    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        ' This fires on a thread from the CLR thread pool.
        ' You can't access the form here or any shared data (like form-level variables).

        ' Retrieve the input arguments.
        Dim Input As RandomNumberGeneratorInput = CType(e.Argument, RandomNumberGeneratorInput)

        ' Create a StringBuilder to hold the generator random number sequence.
        Dim ResultString As New System.Text.StringBuilder()

        ' Calculate the number of iterations needed to make a 1% progress change.
        Dim ProgressIteration As Integer = Input.NumberOfDigits / 100

        ' Start generating numbers.
        For i As Integer = 0 To Input.NumberOfDigits - 1
            If BackgroundWorker1.CancellationPending Then
                e.Cancel = True
                ' Return without doing any more work.
                Return
            End If

            If BackgroundWorker1.WorkerReportsProgress And ProgressIteration > 0 Then
                If i Mod ProgressIteration = 0 Then
                    BackgroundWorker1.ReportProgress(i / ProgressIteration)
                End If
            End If

            ' Create a cryptographically secure random number.
            Dim RandomByte(1000) As Byte
            Dim Random As New System.Security.Cryptography.RNGCryptoServiceProvider()

            ' Fill the byte array with random bytes. In this case,
            ' the byte array only needs a single byte.
            ' We fill it with 1000 just to make sure this is the world's slowest
            ' random number generator.
            Random.GetBytes(RandomByte)

            ' Convert the random byte into a decimal from MinValue to MaxValue.
            Dim RandomDigit As Integer
            RandomDigit = Int(RandomByte(0) / 256 * (Input.MaxValue - Input.MinValue + 1)) + Input.MinValue

            ' Add the random number to the string.
            ResultString.Append(RandomDigit.ToString())
        Next

        ' Return the complete string.
        e.Result = ResultString.ToString()
    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        ' This fires on the main application thread.
        ' It's now safe to update the form.
        If e.Cancelled Then
            MessageBox.Show("Task cancelled.")
        Else
            MessageBox.Show("Task complete.")
            txtResult.Text = CType(e.Result, String)
        End If

        cmdDoWork.Enabled = True
        ProgressBar1.Visible = False
    End Sub

    Private Sub cmdDoWork_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdDoWork.Click
        BackgroundWorker1.WorkerReportsProgress = True
        BackgroundWorker1.WorkerSupportsCancellation = True
        ProgressBar1.Value = 0
        ProgressBar1.Visible = True

        ' Prevent two asynchronous tasks from being triggered at once.
        ' This is allowed, but doesn't make sense in this application.
        cmdDoWork.Enabled = False

        ' Clear any previous results.
        txtResult.Text = ""

        ' Start the asynchronous task.
        Dim Input As New RandomNumberGeneratorInput(Val(txtNumberOfDigits.Text), Val(txtMin.Text), Val(txtMax.Text))
        BackgroundWorker1.RunWorkerAsync(Input)
    End Sub


    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        ProgressBar1.Value = e.ProgressPercentage
    End Sub

    Private Sub cmdCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdCancel.Click
        BackgroundWorker1.CancelAsync()
    End Sub
End Class
