user7747311
user7747311

Reputation:

How to keep a form responsive whilst a Do Loop statement is running

If you run the following code you will see that you can not click Button2 whilst the Do[...]Loop statement is running:

Imports Microsoft.Office.Interop

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

        Dim xlApp As New Excel.Application
        xlApp.Visible = True
        Dim wb1 As Excel.Workbook
        wb1 = xlApp.Workbooks.Open("C:\Book1.xlsx")


        Dim wsSheet1 As Excel.Worksheet
        wsSheet1 = CType(wb1.Sheets(1), Excel.Worksheet)

        Do
            wsSheet1.Cells.Copy()
            wsSheet1.Cells.PasteSpecial(Paste:=Excel.XlPasteType.xlPasteValues)
        Loop

    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        MsgBox("Hello")
    End Sub

End Class

How do you keep Form1 responsive whilst the Do[...]Loop statement is running?

Upvotes: 1

Views: 724

Answers (2)

Bugs
Bugs

Reputation: 4489

In order to keep your form responsive whilst the Do[...]Loop statement is running you need to run it on a separate thread using the Task class.

First create a new method and place the Do[...]Loop statement in that method:

Private Sub CopyCells(ByVal worksheet As Excel.Worksheet)

    Do
        worksheet.Cells.Copy()
        worksheet.Cells.PasteSpecial(Paste:=Excel.XlPasteType.xlPasteValues)
    Loop

End Sub

You can then call this method using Task.Factory.StartNew:

Task.Factory.StartNew(Sub() CopyCells(wsSheet1))

I would also move away from using MsgBox and use MessageBox.Show. MsgBox exists for VB6 and ends up delegating to MessageBox anyway so makes sense to use MessageBox.Show:

MessageBox.Show("Hello")

In full your code would look something similar to this:

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

        Dim xlApp As New Excel.Application
        xlApp.Visible = True

        Dim wb1 As Excel.Workbook
        wb1 = xlApp.Workbooks.Open("C:\Book1.xlsx")

        Dim wsSheet1 As Excel.Worksheet
        wsSheet1 = CType(wb1.Sheets(1), Excel.Worksheet)

        Task.Factory.StartNew(Sub() CopyCells(wsSheet1))

    End Sub

    Private Sub CopyCells(ByVal worksheet As Excel.Worksheet)

        Do
            worksheet.Cells.Copy()
            worksheet.Cells.PasteSpecial(Paste:=Excel.XlPasteType.xlPasteValues)
        Loop

    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        MessageBox.Show("Hello")
    End Sub

End Class

Note that you will have to import System.Threading.Tasks to make use of the Task class.

Upvotes: 0

user1234433222
user1234433222

Reputation: 996

From what I have read, it sounds like your UI is becoming unresponsive when you are asking your program to do a particular task

In this case you should look into the Background Workerexamples on msdn or you could use another thread without using the Background Worker, it really your choice.

Here is a quick example I have written up that will draw rectangle boxes to the screen in a random position using a different thread, this will allow you to move the window around while it draws to the screen and to interact with other components and have them work correctly without it freezing such as a MessageBox.

Imports System.ComponentModel
Public Class Form1
Dim random0 As New Random
Dim thread0 As New Threading.Thread(New Threading.ThreadStart(AddressOf threadDrawing0))

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    thread0.Start()
End Sub
Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
    thread0.Abort()
End Sub

Private Sub threadDrawing0()
    For i = 0 To 1000
        System.Threading.Thread.Sleep(100)
        Me.CreateGraphics().DrawRectangle(New Pen(Brushes.Blue, 4), New Rectangle(random0.Next(0, Me.Width), random0.Next(0, Me.Height), 20, 20))
    Next
End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    MessageBox.Show("Hello World")
End Sub
End Class

Because I dont have the excel file you are working with, I am unable to test the code to your exact needs, however this should well and truly get you on the right path.

MSDN Background Worker Link : https://msdn.microsoft.com/es-es/library/cc221403(v=vs.95).aspx

Upvotes: 1

Related Questions