多线程进度条更新解决方案

在现代应用程序中,用户界面(UI)的响应性至关重要。当执行长时间运行的任务时,如文件加密、大数据处理等,如果UI没有及时反馈,用户可能会认为程序已经崩溃或无响应。因此,实现一个有效的进度条更新机制对于提升用户体验至关重要。本文将介绍一种在VB.NET中实现多线程进度条更新解决方案

本文是2011年5月4日发表的同名文章的续篇。原文章试图寻找解决方案,而本文则是经过六个月测试的最终解决方案。

使用代码

示例代码稍作抽象,但通过修改特定参数即可运行。在这个例子中,假设有一个加密文件的过程,它需要三个额外的参数作为输入。如果过程中没有错误,该过程将返回0;如果有错误,则返回非零值。示例代码还提供了一个取消按钮。这段代码适用于非常大的文件,以及那些不提供中间返回值以更新进度条的过程。代码分为两个类:主线程类和线程包装器,后者用于启动新线程并返回完成值。还有一个额外的类,用于获取文件的哈希值,以演示返回数据而不是整数完成值。

以下代码示例展示了如何通过为长时间运行的过程创建新线程,同时在主线程更新进度条,来实现进度条。在这个例子中,长时间运行的过程是一个API调用,它在完成之前不会返回,并返回一个整数来指示错误或成功。

Option Strict Off Option Explicit On Imports Microsoft.VisualBasic Imports System Imports System.IO Imports System.Threading Public Delegate Sub CallbackToEnc(ByVal var1 As Integer) Public Delegate Sub CallbackToHash(ByVal fileHash As String) Public Class Protect Public rtnBlfResult As Integer Public Shared Sub ResultCallback(ByVal var1 As Integer) CProtect.rtnBlfResult = var1 End Sub Public Function Encrypter(ByVal file1 As String, ByVal file2 As String, ByVal param1 As String, ByVal param2 As Integer, ByVal param3 As String) As Short Dim iAbortLock As Boolean = False Dim time1 As Single = 0 Dim time2 As Single = 0 CProtect.rtnBlfResult = -2 ' Initialize return. Dim tw1 As New TWrapEnc(file1, file2, param1, param2, param3, New CallbackToEnc(AddressOf ResultCallback)) tw1.start() T1: time2 = Timer If cancelBttnSequence = 3 Then If iAbortLock = False Then tw1.thread.Abort() iAbortLock = True time1 = Timer End If End If If tw1.thread.ThreadState = System.Threading.ThreadState.Stopped Then GoTo T2 End If If time1 > 0 AndAlso (Timer - time1) > 5 Then GoTo T2a End If If (Timer - time1) < 0 Then time1 = Timer End If If (Timer - time2) < 0 Then time2 = Timer End If While (Timer - time2) < 1 SyncLock tw1.rtnLockEnc If CProtect.rtnBlfResult = -1 Then GoTo T2 End If End SyncLock End While UpdatePgrBar() GoTo T1 T2: tw1.join() T2a: tw1 = Nothing rtnBlfResult = CProtect.rtnBlfResult If rtnBlfResult = 0 Then Encrypter = -1 ' Successful, file2 contains encrypted form of file1. ElseIf iAbortLock = True Then Encrypter = -2 ' Cancel. Else Encrypter = 0 ' Error. End If End Function Public Shared Sub UpdatePgrBar() ' Some code to update progress bar. End Sub End Class Public Class TWrapEnc Private fileX1 As String Private fileX2 As String Private paramX1 As String Private paramX2 As Integer Private paramX3 As String Private blfRtnParam As Integer = -1 Private callBack As CallbackToEnc Public rtnLockEnc As New Object Public thread As System.Threading.Thread Public Sub New(ByVal file1 As String, ByVal file2 As String, ByVal param1 As String, ByVal param2 As Integer, ByVal param3 As String, ByVal callBackDelegate As CallbackToEnc) fileX1 = file1 fileX2 = file2 paramX1 = param1 paramX2 = param2 paramX3 = param3 callBack = callBackDelegate thread = New System.Threading.Thread(AddressOf body) End Sub Public Sub start() Me.thread.Start() End Sub Public Sub join() Me.thread.Join() End Sub Public Sub body() On Error GoTo E1 Me.blfRtnParam = Blowfish.FileEncrypt(Me.fileX1, Me.fileX2, Me.paramX1, Me.paramX2, Me.paramX3) E1: SyncLock rtnLockEnc If Not callBack Is Nothing Then callBack(Me.blfRtnParam) End If End SyncLock Me.fileX1 = "" Me.fileX2 = "" Me.paramX1 = "" End Sub End Class Public Class ThreadWrapperHash Private fileNameParam As String Private callback As CallbackToHash Private fileHashRtnParam As String Public rtnLockHash As New Object Public thread As System.Threading.Thread Public Sub New(ByVal fileName As String, ByVal callbackDelegate As CallbackToHash) fileNameParam = fileName callback = callbackDelegate thread = New System.Threading.Thread(AddressOf Body) End Sub Public Sub start() Me.thread.Start() End Sub Public Sub join() Me.thread.Join() End Sub Public Sub Body() On Error GoTo CallB Me.fileHashRtnParam = Sha256.FileHexHash(Me.fileNameParam) CallB: SyncLock rtnLockHash If Not callback Is Nothing Then callback(Me.fileHashRtnParam) End If End SyncLock Me.fileNameParam = "" End Sub End Class
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485