首页 > 其他 > 详细

CF下的BackgroudWorker组件优化.

时间:2014-03-12 20:46:04      阅读:441      评论:0      收藏:0      [点我收藏+]

.net compact framwork(2.0/3.5)下没有Backgroundworder组件,在网上找了一个类

经过使用发现了一些问题,主要有一个问题:在一个Dowork事件中对ReportProgress 多次输出时可能无法正确完成.

花了点时间对该类进行了修改,将ReportProgress的参数进行队列处理,在实际处理Progress时采用循环检测.用了 Queue功能.

bubuko.com,布布扣
 
#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
bubuko.com,布布扣

CF下的BackgroudWorker组件优化.,布布扣,bubuko.com

CF下的BackgroudWorker组件优化.

原文:http://www.cnblogs.com/nbsamson/p/3596999.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!