تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
نظرة عامة حول Event-based Asynchronous Pattern
#3
وهذا هو كود ال Component الخاص بنا:



كود :
Imports System.IO
Imports System.Threading
Imports System.ComponentModel
Imports System.Collections.Specialized

Public Class AsynchronousStreamCopy
Inherits Component

#Region "Events"

Public Custom Event StreamCopyProgressChanged As StreamCopyProgressChangedEventHandler
AddHandler(ByVal value As StreamCopyProgressChangedEventHandler)
SyncLock ChangedLock
Me.Events.AddHandler(ChangedLock, value)
End SyncLock
End AddHandler

RemoveHandler(ByVal value As StreamCopyProgressChangedEventHandler)
SyncLock ChangedLock
Me.Events.RemoveHandler(ChangedLock, value)
End SyncLock
End RemoveHandler

RaiseEvent(ByVal e As StreamCopyProgressChangedEventArgs)
Dim handler As StreamCopyProgressChangedEventHandler = Nothing
SyncLock ChangedLock
handler = Me.Events(ChangedLock)
End SyncLock
If handler IsNot Nothing Then
handler(e)
End If
End RaiseEvent

End Event
Public Custom Event StreamCopyCompleted As StreamCopyCompletedEventHandler
AddHandler(ByVal value As StreamCopyCompletedEventHandler)
SyncLock CompletedLock
Me.Events.AddHandler(CompletedLock, value)
End SyncLock
End AddHandler

RemoveHandler(ByVal value As StreamCopyCompletedEventHandler)
SyncLock CompletedLock
Me.Events.RemoveHandler(CompletedLock, value)
End SyncLock
End RemoveHandler

RaiseEvent(ByVal e As AsyncCompletedEventArgs)
Dim handler As StreamCopyCompletedEventHandler = Nothing
SyncLock CompletedLock
handler = Me.Events(CompletedLock)
End SyncLock
If handler IsNot Nothing Then
handler.Invoke(e)
End If
End RaiseEvent
End Event

#End Region

#Region "Delegates"

Private Delegate Sub Worker(ByVal container As StreamsContainer)

#End Region

#Region "Fields"

Private OnCopyCompletedDelegate As SendOrPostCallback
Private OnCopyProgressChangedDelegate As SendOrPostCallback
Protected TasksHash As New HybridDictionary
Private Const _defaultId As String = "Default"
Private ReadOnly _buffersize As Integer = &H1000
Private components As IContainer = Nothing
Private ReadOnly ChangedLock As New Object()
Private ReadOnly CompletedLock As New Object()

#End Region

#Region "Constructors"

Public Sub New()
MyBase.New()
InitializeDelegates()
End Sub

Public Sub New(ByVal container As IContainer)
Me.New()
container.Add(Me)
End Sub

Public Sub New(ByVal container As IContainer, ByVal buferrsize As Integer)
Me.New(container)
Me._buffersize = _buffersize
End Sub

Public Sub New(ByVal container As IContainer, ByVal buffersize As Integer, ByVal sc As SynchronizationContext)
Me.New(container, buffersize)
AsyncOperationManager.SynchronizationContext = sc
End Sub

Public Sub New(ByVal sc As SynchronizationContext)
Me.New()
AsyncOperationManager.SynchronizationContext = sc
End Sub

Public Sub New(ByVal buffersize As Integer)
Me.New()
Me._buffersize = buffersize
End Sub


Prvate Sub InitializeDelegates()
OnCopyCompletedDelegate = New SendOrPostCallback(AddressOf CopyCompleted)
OnCopyProgressChangedDelegate = New SendOrPostCallback(AddressOf CopyProgressChanged)
End Sub

#End Region

#Region "Methods"

Public Overloads Sub CopyStreamAsync(ByVal sourceStream As Stream, ByVal destinationStream As Stream)
CopyStreamAsync(sourceStream, destinationStream, _defaultId)
End Sub

Public Overloads Sub CopyStreamAsync(ByVal sourceStream As Stream _
, ByVal destination As Stream _
, ByVal taskId As Object)

Dim operation As AsyncOperation = AsyncOperationManager.CreateOperation(taskId)

SyncLock TasksHash.SyncRoot
If TasksHash.Contains(taskId) Then
If taskId Is _defaultId Then
Throw New InvalidOperationException("Worker is busy")
End If
Throw New Exception("Task already exists")
End If
TasksHash(TaskId) = operation
End SyncLock

Dim container As New StreamsContainer(sourceStream, destination, operation, _buffersize)

Dim worker As New Worker(AddressOf StartCopy)
worker.BeginInvoke(container, Nothing, Nothing)

End Sub

Private Function TaskExists(ByVal taskId As Object) As Boolean
Return Not TasksHash(taskId) Is Nothing
End Function

Private Sub StartCopy(ByVal container As StreamsContainer)

If TaskExists(container.Operation.UserSuppliedState) Then
Try
Dim source = container.SourceStream
source.BeginRead(container.Buffer, 0, container.Buffer.Length _
, New AsyncCallback(AddressOf ReadEnd), container)
Catch ex As Exception
Me.CompleteCopy(container, ex, False)
End Try
Else
Throw New InvalidOperationException("Task doesn't exist.")
End If
End Sub


Private Sub ReadEnd(ByVal results As IAsyncResult)

Dim container = CType(results.AsyncState, StreamsContainer)
Try
Dim read = container.SourceStream.EndRead(results)
container.Position += read
If TaskExists(container.Operation.UserSuppliedState) Then
If read = 0 Then
Me.CompleteCopy(container, Nothing, False)
Else
container.DestinationStream.BeginWrite( _
container.Buffer, 0, container.Buffer.Length, _
New AsyncCallback(AddressOf Me.WriteEnd), container)
End If
Else
Me.CompleteCopy(container, Nothing, True)
End If
Catch ex As Exception
Me.CompleteCopy(container, ex, False)
End Try

End Sub


Private Sub WriteEnd(ByVal results As IAsyncResult)
Dim container = CType(results.AsyncState, StreamsContainer)
If TaskExists(container.Operation.UserSuppliedState) Then
Try
container.DestinationStream.EndWrite(results)
Dim percentage As Integer = _
container.Position / container.SourceStream.Length * 100
Dim e As New StreamCopyProgressChangedEventArgs(container.Position _
, container.Operation.UserSuppliedState, percentage)
container.Operation.Post(OnCopyProgressChangedDelegate, e)
container.SourceStream.BeginRead(container.Buffer, _
0, container.Buffer.Length, _
New AsyncCallback(AddressOf Me.ReadEnd), container)

Catch ex As Exception
Me.CompleteCopy(container, ex, False)
End Try
Else
Me.CompleteCopy(container, Nothing, True)
End If

End Sub


Private Sub CompleteCopy(ByVal container As StreamsContainer _
, ByVal exc As Exception _
, ByVal canceled As Boolean)

SyncLock TasksHash.SyncRoot
If TaskExists(container.Operation.UserSuppliedState) Then
TasksHash.Remove(container.Operation.UserSuppliedState)
End If
End SyncLock

Dim e As New AsyncCompletedEventArgs(exc, _
canceled, container.Operation.UserSuppliedState)

container.Operation.PostOperationCompleted(OnCopyCompletedDelegate, e)

End Sub


Private Sub CopyCompleted(ByVal e As AsyncCompletedEventArgs)
OnCopyProgressCompleted(e)
End Sub

Private Sub CopyProgressChanged(ByVal e As StreamCopyProgressChangedEventArgs)
OnCopyProgressChanged(e)
End Sub

Protected Overridable Sub OnCopyProgressChanged(ByVal e As StreamCopyProgressChangedEventArgs)
RaiseEvent StreamCopyProgressChanged(e)
End Sub

Protected Overridable Sub OnCopyProgressCompleted(ByVal e As AsyncCompletedEventArgs)
RaiseEvent StreamCopyCompleted(e)
End Sub

Public Overloads Sub CancelAsync()
CancelAsync(_defaultId)
End Sub

Public Overloads Sub CancelAsync(ByVal userState As Object)
If userstate Is Nothing Then
Throw New ArgumentNullException("userState")
End If
If Not TaskExists(userstate) Then
Throw New ArgumentException("userState doesn't exist.")
End If
SyncLock TasksHash
TasksHash.Remove(userstate)
End SyncLock
End Sub

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not components Is Nothing Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

#End Region

#Region "Properties"

Public ReadOnly Property BufferSize() As Integer
Get
Return _buffersize
End Get
End Property

#End Region

End Class
المثال التالي يوضح كيفي استخدام ال Component السابق للقيام بنسخ عدة ملفات بشكل متتالي الواحد تلو الآخر:

كود :
Imports StreamCopyAsync
Imports System.ComponentModel
Imports System.Windows
Imports System.IO
Imports System.Threading

Public Class Form1

Dim mre As ManualResetEvent

Private Sub _AsyncCopy_StreamCopyCompleted(ByVal e As AsyncCompletedEventArgs) Handles _AsyncCopy.StreamCopyCompleted
If e.Error IsNot Nothing Then
MessageBox.Show(e.Error.Message)
Me.lblStatus.Text = "Copy was not successful."
ElseIf e.Cancelled Then
Me.lblStatus.Text = "Copy canceled."
Else
Me.lblStatus.Text = "Copy completed successfully."
End If
If Not mre.SafeWaitHandle.IsClosed Then
mre.Set()
End If
End Sub

Private Sub _AsyncCopy_StreamCopyProgressChanged(ByVal e As StreamCopyProgressChangedEventArgs) Handles _AsyncCopy.StreamCopyProgressChanged
Me.ProgressBar1.Value = e.ProgressPercentage
Me.lblStatus.Text = e.BytesCopied & " bytes copied. Total progress: " & e.ProgressPercentage & " %"
End Sub

Private Sub BtnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnstart.Click
ThreadPool.QueueUserWorkItem(AddressOf StartCopy)
End Sub

Private Sub BtnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btncancel.Click
_AsyncCopy.CancelAsync()
mre.Reset();
mre.Dispose()
End Sub

Sub StartCopy()

Dim Sources As IEnumerable(Of FileStream) = _
My.Computer.FileSystem.GetFiles("D:") _
.Select(Function(x) File.OpenRead(x))

Dim destination As IEnumerable(Of FileStream) = _
My.Computer.FileSystem.GetFiles("D:") _
.Select(Function(x) File.OpenWrite(x.Replace("D:\", "D:\Copy of ")))

mre = New Semaphore(False)

Using SourceEnum = Sources.GetEnumerator, _
DestnationEnum = destination.GetEnumerator

While SourceEnum.MoveNext AndAlso DestnationEnum.MoveNext
Using CurrentSource = SourceEnum.Current, _
CurrentDest = DestnationEnum.Current

_AsyncCopy.CopyStreamAsync(SourceEnum.Current, DestnationEnum.Current)

mre.Dispose()
End Using
End While
End Using
sema = Nothing
End Sub

End Class
طبعاً يمكنكم استخدام الأداة على تطبيق WPF أو حتى ASP.NET فقط كل ماعليك هو تعريف نسخة من ال Component السابق واستخدامه بالشكل المناسب لك.
}}}
تم الشكر بواسطة:


الردود في هذا الموضوع
نظرة عامة حول Event-based Asynchronous Pattern - بواسطة Raggi Tech - 08-10-12, 05:44 PM

المواضيع المحتمل أن تكون متشابهة .
الموضوع : الكاتب الردود : المشاهدات : آخر رد
  نظرة سريعة في الجديد في Visual Studio 2008 فيما يتعلق ببيئة التطوير RaggiTech 0 2,078 08-10-12, 05:45 PM
آخر رد: RaggiTech
  نظرة على جديد الفيجوال بيسك 9 - الجزء الأول RaggiTech 0 2,253 08-10-12, 05:38 PM
آخر رد: RaggiTech

التنقل السريع :


يقوم بقرائة الموضوع: