.net compact framwork(2.0/3.5)下没有Backgroundworder组件,在网上找了一个类
经过使用发现了一些问题,主要有一个问题:在一个Dowork事件中对ReportProgress 多次输出时可能无法正确完成.
花了点时间对该类进行了修改,将ReportProgress的参数进行队列处理,在实际处理Progress时采用循环检测.用了 Queue功能.
#Region "EventArgs classes" Public Class RunWorkerCompletedEventArgs Inherits System.EventArgs ‘ This class should inherit from AsyncCompletedEventArgs but I don‘t see the point in the CF‘s case Private ReadOnly mResult As Object Private ReadOnly mCancelled As Boolean Private ReadOnly mError As System.Exception Public Sub New(ByVal aResult As Object, ByVal aError As System.Exception, ByVal aCancelled As Boolean) mResult = aResult mError = aError mCancelled = aCancelled End Sub Public ReadOnly Property Result() As Object Get Return mResult End Get End Property Public ReadOnly Property Cancelled() As Boolean Get Return mCancelled End Get End Property Public ReadOnly Property [Error]() As System.Exception Get Return mError End Get End Property End Class Public Class ProgressChangedEventArgs Inherits System.EventArgs Private ReadOnly mProgressPercent As Int32 Private ReadOnly mUserState As Object Public Sub New(ByVal aProgressPercent As Int32, ByVal aUserState As Object) mProgressPercent = aProgressPercent mUserState = aUserState End Sub Public ReadOnly Property ProgressPercentage() As Int32 Get Return mProgressPercent End Get End Property Public ReadOnly Property UserState() As Object Get Return mUserState End Get End Property End Class Public Class DoWorkEventArgs Inherits System.ComponentModel.CancelEventArgs Private ReadOnly mArgument As Object Private mResult As Object Public Sub New(ByVal aArgument As Object) mArgument = aArgument End Sub Public ReadOnly Property Argument() As Object Get Return mArgument End Get End Property Public Property Result() As Object Get Return mResult End Get Set(ByVal value As Object) mResult = value End Set End Property End Class #End Region #Region "Delegates for 3 events of class" Public Delegate Sub DoWorkEventHandler(ByVal sender As Object, ByVal e As DoWorkEventArgs) Public Delegate Sub ProgressChangedEventHandler(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Public Delegate Sub RunWorkerCompletedEventHandler(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) #End Region #Region "BackgroundWorker Class" ‘‘‘ <summary> ‘‘‘ Executes an operation on a separate thread. ‘‘‘ </summary> Public Class BackgroundWorker Inherits System.ComponentModel.Component #Region "Public Interface" Public Event DoWork As DoWorkEventHandler Public Event ProgressChanged As ProgressChangedEventHandler Public Event RunWorkerCompleted As RunWorkerCompletedEventHandler Private _eventarg As System.Collections.Generic.Queue(Of ProgressChangedEventArgs) ‘‘‘ <summary> ‘‘‘ Initializes a new instance of the BackgroundWorker class. ‘‘‘ </summary> Public Sub New() Me.New(New System.Windows.Forms.Control) _eventarg = New System.Collections.Generic.Queue(Of ProgressChangedEventArgs) ‘ ideally we want to call Control.CreateControl() ‘ without it, running on the desktop will crash (it is OK on the CF) ‘ [on the full fx simply calling a control‘s constructor does not create the Handle.] ‘ The CreateControl method is not supported on the CF so to keep this assembly retargettable ‘ I have offered the alternative ctor for desktop clients ‘ (where they can pass in already created controls) End Sub ‘‘‘ <summary> ‘‘‘ Initializes a new instance of the BackgroundWorker class. ‘‘‘ Call from the desktop code as the other ctor is not good enough ‘‘‘ Call it passing in a created control e.g. the Form ‘‘‘ </summary> Public Sub New(ByVal aControl As System.Windows.Forms.Control) MyBase.New() mGuiMarshaller = aControl End Sub ‘‘‘ <summary> ‘‘‘ Gets a value indicating whether the application has requested cancellation of a background operation. ‘‘‘ </summary> Public ReadOnly Property CancellationPending() As Boolean Get Return mCancelPending End Get End Property ‘‘‘ <summary> ‘‘‘ Raises the BackgroundWorker.ProgressChanged event. ‘‘‘ </summary> ‘‘‘ <param name="aProgressPercent">The percentage, from 0 to 100, of the background operation that is complete. </param> Public Sub ReportProgress(ByVal aProgressPercent As Int32) Me.ReportProgress(aProgressPercent, Nothing) End Sub ‘‘‘ <summary> ‘‘‘ Raises the BackgroundWorker.ProgressChanged event. ‘‘‘ </summary> ‘‘‘ <param name="aProgressPercent">The percentage, from 0 to 100, of the background operation that is complete. </param> ‘‘‘ <param name="aUserState">The state object passed to BackgroundWorker.RunWorkerAsync(System.Object).</param> Public Sub ReportProgress(ByVal aProgressPercent As Int32, ByVal aUserState As Object) If Not mDoesProgress Then Throw New System.InvalidOperationException("Doesn‘t do progress events. You must WorkerReportsProgress=True") End If ‘ Send the event to the GUI _eventarg.Enqueue(New ProgressChangedEventArgs(aProgressPercent, aUserState)) System.Threading.ThreadPool.QueueUserWorkItem( _ New System.Threading.WaitCallback(AddressOf ProgressHelper)) End Sub ‘‘‘ <summary> ‘‘‘ Starts execution of a background operation. ‘‘‘ </summary> Public Sub RunWorkerAsync() Me.RunWorkerAsync(Nothing) End Sub Public ReadOnly Property IsBusy() As Boolean Get Return mInUse End Get End Property ‘‘‘ <summary> ‘‘‘ Starts execution of a background operation. ‘‘‘ </summary> ‘‘‘ <param name="aArgument"> A parameter for use by the background operation to be executed in the BackgroundWorker.DoWork event handler.</param> Public Sub RunWorkerAsync(ByVal aArgument As Object) If mInUse Then Throw New System.InvalidOperationException("Already in use.") End If If DoWorkEvent Is Nothing Then Throw New System.InvalidOperationException("You must subscribe to the DoWork event.") End If mInUse = True mCancelPending = False System.Threading.ThreadPool.QueueUserWorkItem( _ New System.Threading.WaitCallback(AddressOf DoTheRealWork), aArgument) End Sub ‘‘‘ <summary> ‘‘‘ Requests cancellation of a pending background operation. ‘‘‘ </summary> Public Sub CancelAsync() If Not mDoesCancel Then Throw New System.InvalidOperationException("Does not support cancel. You must WorkerSupportsCancellation=True") End If mCancelPending = True End Sub ‘‘‘ <summary> ‘‘‘ Gets or sets a value indicating whether the BackgroundWorker object can report progress updates. ‘‘‘ </summary> Public Property WorkerReportsProgress() As Boolean Get Return mDoesProgress End Get Set(ByVal value As Boolean) mDoesProgress = value End Set End Property ‘‘‘ <summary> ‘‘‘ Gets or sets a value indicating whether the BackgroundWorker object supports asynchronous cancellation. ‘‘‘ </summary> Public Property WorkerSupportsCancellation() As Boolean Get Return mDoesCancel End Get Set(ByVal Value As Boolean) mDoesCancel = Value End Set End Property #End Region #Region "Fields" ‘Ensures the component is used only once per session Private mInUse As Boolean ‘Stores the cancelation request that the worker thread (user‘s code) should check via CancellationPending Private mCancelPending As Boolean ‘Whether the object supports cancelling or not (and progress or not) Private mDoesCancel As Boolean Private mDoesProgress As Boolean ‘Helper objects since Control.Invoke takes no arguments Private mFinalResult As RunWorkerCompletedEventArgs Private mProgressArgs As ProgressChangedEventArgs ‘Private mProgressArgsList As New List(Of ProgressChangedEventArgs) ‘ Helper for marshalling execution to GUI thread Private mGuiMarshaller As System.Windows.Forms.Control #End Region #Region "Private Methods" ‘ Async(ThreadPool) called by ReportProgress for reporting progress Private Sub ProgressHelper() Dim t As System.Windows.Forms.Control = mGuiMarshaller t.Invoke(New System.EventHandler(AddressOf TellThemOnGuiProgress)) End Sub ‘ ControlInvoked by ProgressHelper for raising progress Private Sub TellThemOnGuiProgress(ByVal sender As Object, ByVal e As System.EventArgs) Dim o As ProgressChangedEventArgs While _eventarg.Count > 0 o = _eventarg.Dequeue() If o IsNot Nothing Then RaiseEvent ProgressChanged(sender, o) End If End While End Sub ‘ Async(ThreadPool) called by RunWorkerAsync [the little engine of this class] Private Sub DoTheRealWork(ByVal o As Object) ‘ declare the vars we will pass back to client on completion Dim er As System.Exception = Nothing Dim ca As Boolean Dim result As Object = Nothing ‘ Raise the event passing the original argument and catching any exceptions Try Dim inOut As New DoWorkEventArgs(o) RaiseEvent DoWork(Me, inOut) ca = inOut.Cancel result = inOut.Result Catch ex As System.Exception er = ex End Try ‘ store the completed final result in a temp var Dim tempResult As New RunWorkerCompletedEventArgs(result, er, ca) ‘ return execution to client by going async here System.Threading.ThreadPool.QueueUserWorkItem( _ New System.Threading.WaitCallback(AddressOf RealWorkHelper), tempResult) ‘ prepare for next use mInUse = False mCancelPending = False End Sub ‘ Async(ThreadPool) called by DoTheRealWork [to avoid any rentrancy issues at the client end] Private Sub RealWorkHelper(ByVal o As Object) mFinalResult = DirectCast(o, RunWorkerCompletedEventArgs) mGuiMarshaller.Invoke(New System.EventHandler(AddressOf TellThemOnGuiCompleted)) End Sub ‘ ControlInvoked by RealWorkHelper for raising final completed event Private Sub TellThemOnGuiCompleted(ByVal sender As Object, ByVal e As System.EventArgs) RaiseEvent RunWorkerCompleted(Me, mFinalResult) End Sub #End Region End Class #End Region
CF下的BackgroudWorker组件优化.,布布扣,bubuko.com
原文:http://www.cnblogs.com/nbsamson/p/3596999.html