【问题标题】:How to keep a form responsive whilst a Do Loop statement is running如何在 Do Loop 语句运行时保持表单响应
【发布时间】:2017-04-06 06:02:18
【问题描述】:

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

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

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

【问题讨论】:

  • 如果您希望您的 UI 在长时间运行的任务期间响应,那么您必须使用辅助线程。这可以通过多种方式完成,包括使用 Task 类。
  • 很遗憾,这不是编码服务。您需要自己尝试一下,然后如果您遇到问题,有人可以帮助您解决问题。

标签: vb.net multithreading winforms


【解决方案1】:

根据我的阅读,当您要求程序执行特定任务时,您的 UI 似乎变得无响应

在这种情况下,您应该查看 msdn 上的 Background Workerexamples 或者您可以在不使用 Background Worker 的情况下使用另一个线程,这确实是您的选择。

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

【讨论】:

    【解决方案2】:

    为了在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.ShowMsgBox 存在于 VB6 并最终委托给 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 类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-31
      • 1970-01-01
      相关资源
      最近更新 更多