如何在Do Loop语句运行时保持表单响应

时间:2017-04-06 06:02:18

标签: vb.net multithreading winforms

如果您运行以下代码,您将看到在Button2语句正在运行时无法单击Do[...]Loop

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

Form1语句运行时如何保持Do[...]Loop响应?

2 个答案:

答案 0 :(得分:1)

根据我的阅读,当您要求程序执行特定任务时,听起来您的UI变得反应迟钝了
在这种情况下,您应该查看Background Worker示例在msdn或你可以使用另一个线程而不使用后台工作者,它真的是你的选择。

这是我写的一个快速示例,它将使用一个随机位置将矩形框绘制到屏幕上不同的线程,这将允许您在绘制到屏幕时移动窗口并与其他组件交互,让它们正常工作而不会冻结,如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

因为我没有您正在使用的excel文件,所以我无法根据您的确切需求测试代码,但这应该能够真正让您走上正确的道路。

MSDN背景工人链接:https://msdn.microsoft.com/es-es/library/cc221403(v=vs.95).aspx

答案 1 :(得分:0)

为了在Do[...]Loop语句运行时保持表单响应,您需要使用Task类在单独的线程上运行它。

首先创建一个新方法并将Do[...]Loop语句放在该方法中:

Private Sub CopyCells(ByVal worksheet As Excel.Worksheet)

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

End Sub

然后,您可以使用Task.Factory.StartNew调用此方法:

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

我也会放弃使用MsgBox并使用MessageBox.Show。 VB6存在MsgBox,无论如何最终委托给MessageBox,因此使用MessageBox.Show是有道理的:

MessageBox.Show("Hello")

完整的代码看起来与此类似:

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
  

请注意,您必须导入System.Threading.Tasks才能使用Task类。