vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
sevDataGrid - G?nnen Sie Ihrem SQL-Kommando diesen kr?nenden Abschlu?!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   RSS-Feeds  | Newsletter  | Impressum  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2014
 
zurück
Rubrik: Verschiedenes / Sonstiges   |   VB-Versionen: VB.NET07.02.06
Multithreading mit VB.NET 2005

Asynchrone Dateioperationen mit Multithreading verwirklichen

Autor:   Stefan MährBewertung:     [ Jetzt bewerten ]Views:  29.941 
www.visualsoft-net.deSystem:  WinNT, Win2k, WinXP, Vista, Win7, Win8 Beispielprojekt auf CD 

Mit .NET brachte Microsoft den heiligen Gral des Mutlithreadings zu den VB Programmierern. Bis dahin mußten wir uns mit DoEvents vor UI Lockups bewahren, oder noch schlimmer Out Of Process ActiveX-Exen programmieren um diese zu verhinden. Programmieren mit Threads bringt jedoch neue Probleme mit sich wie Deadlocks, nicht mehr ansprechbare Controls da diese in einem anderen Thread laufen usw.

Dieses kleine VB.NET 2005 Beispiel sollte einen kleinen übersichtlichen Einstieg in das Programmieren mit dem Backgroundworkerthread bieten. Das Beispiel sollte eine große Datei byteweise in einem eigenen Thread kopieren und dabei einen Progress darstellen. Die Operation sollte natürlich jederzeit abbrechbar sein.

Dazu legen wir ein neues Windowsformsprojekt an und legen folgende Controls auf Form1:

  • 2 x Label (lblSource, lblTarget)
  • 4 x CommandButton (cmdSelectSource, cmdSelectTarget, cmdCancel, cmdCopyAsync)
  • 1 x Statusstrip (Statusstrip1, darauf eine progressbar - progress und einen toolstripstatuslabel)
  • 1 x Textbox (txtTest), mit der beweisen wir das die UI nicht einfriert

Nun zum Code:
Wir importieren folgende Namespaces:

Imports System.IO
Imports System.ComponentModel

Private Variablen:

' unser Thread
Private th As BackgroundWorker 
 
' wieviele Bytes wurden kopiert
Private lngBytesCopied As Long 
 
' Die Speicheradresse der Zieldatei
Private lngSourceFileLength As Long

Die Ladeprozedur des Formulares:
Hier richten wir den Backgroundworkerthread ein und stellen den Status der UI her.

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  th = New BackgroundWorker
  AddHandler th.DoWork, AddressOf th_DoWork
  AddHandler th.RunWorkerCompleted, AddressOf th_Completed
  AddHandler th.ProgressChanged, AddressOf th_ProgressChanged				
  th.WorkerReportsProgress = True
  th.WorkerSupportsCancellation = True
 
  Me.lblSource.Text = "<Source File>"
  Me.lblTarget.Text = "<Target File>"
  Me.cmdCopyAsync.Enabled = False
  Me.cmdCancel.Enabled = False
  Me.progress.Visible = False
  Me.lblProgress.Visible = False
End Sub

Die Routinen für das Auswählen der Source und Zieldatei. Eigentlich selbsterklärend.

Private Sub cmdSelectSource_Click(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles cmdSelectSource.Click
 
  Dim openDlg As New OpenFileDialog
  With openDlg
    .Title = "Select file"
    .InitialDirectory = Application.StartupPath
    If .ShowDialog = Windows.Forms.DialogResult.OK Then
      Me.lblSource.Text = .FileName
    End If
  End With
End Sub
Private Sub cmdSelectTarget_Click(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles cmdSelectTarget.Click
 
  Dim fldBrowser As New FolderBrowserDialog
  With fldBrowser
    .ShowNewFolderButton = True
    If .ShowDialog = Windows.Forms.DialogResult.OK Then
      Me.lblTarget.Text = .SelectedPath
      Me.cmdCopyAsync.Enabled = True
    End If
  End With
End Sub

Hier wird der asnchrone Thread gestartet:

Private Sub cmdCopyAsync_Click(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles cmdCopyAsync.Click
 
  If Me.lblTarget.Text.Length > 0 And Me.lblSource.Text.Length > 0 Then
    Me.cmdCopyAsync.Enabled = False
    Me.progress.Minimum = 0
    Me.progress.Maximum = 100
    Me.progress.Visible = True
    Me.lblProgress.Visible = True
    Me.cmdCancel.Enabled = True
 
    ' Start des Threads löst dann die th_DoWork Prozedur aus
    th.RunWorkerAsync() 
  End If
End Sub

So jetzt das eigentliche Arbeitspferd, die th_DoWork Prozedur kopiert die Datei in einem eigenen Thread.

Private Sub th_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
  Dim fi As New FileInfo(Me.lblSource.Text)
 
  Dim inStream As FileStream = Nothing
  Dim outStream As FileStream = Nothing
  Dim buffer(2048) As Byte
  Dim offset As Integer = 0				
 
  Try
    inStream = New FileStream(fi.FullName, FileMode.Open)
    outStream = New FileStream(Me.lblTarget.Text & "\" & fi.Name, FileMode.Create)
    lngSourceFileLength = inStream.Length
    Do
      If th.CancellationPending = True Then
        e.Cancel = True
        inStream.Close()
        outStream.Close()
        Exit Sub
      End If
      offset = inStream.Read(buffer, 0, buffer.Length)
      outStream.Write(buffer, 0, offset)
      lngBytesCopied += offset
 
      ' WICHTIG: Hier könen wir einen Progress darstellen
      th.ReportProgress(offset / inStream.Length * 100)
    Loop Until offset = 0
 
  Catch ex As Exception
    MessageBox.Show(ex.Message)
 
  Finally
    inStream.Close()
    outStream.Close()
  End Try
End Sub

Jetzt stellen wir den Progress dar.
Hierzu stellt uns die BackgroundWorker Klasse eine eigene Prozedur zur Verfügung um Threadsafe auf die Controls des Winforms zuzugreifen.

Private Sub th_ProgressChanged(ByVal sender As Object, _
  ByVal e As ProgressChangedEventArgs)
 
  Try
    Me.lblProgress.Text = lngBytesCopied.ToString & " Bytes From " & _
      lngSourceFileLength.ToString & " Copied"
    Me.progress.Value = e.ProgressPercentage.ToString
  Catch ex As Exception
    MessageBox.Show(ex.Message)
  End Try
End Sub

Die Cancel-Operation:

Private Sub cmdCancel_Click(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles cmdCancel.Click
 
  If th.IsBusy Then
    th.CancelAsync()
  End If
End Sub

Wenn der Thread abgeschlossen ist werden wir in der th_completed inklusive Status davon benachrichtigt.

Private Sub th_Completed(ByVal sender As Object, _
  ByVal e As RunWorkerCompletedEventArgs)
 
  Dim strFinished As String = String.Empty
 
  If e.Cancelled Then
    strFinished = "Operation Cancelled"
  ElseIf e.Error IsNot Nothing Then
    strFinished = "Operation Error " & e.Error.Message
  Else
    strFinished = "Operation Sucessfull"
  End If
 
  MessageBox.Show("CopyThread finished" & vbCrLf & strFinished)
  Me.cmdCopyAsync.Enabled = True
End Sub

Noch eine schnelle Sicherheitsüberprüfung, ob der Thread nicht rennt, wenn das Form geschlossen wird.

Private Sub Form1_FormClosing(ByVal sender As Object, _
  ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
 
  If th.IsBusy Then
    th.CancelAsync()
  End If
End Sub

Man kann das Weiterlaufen der UI schön beobachten, indem man einfach während der Copy-Operation einen Text in die Textbox "txtTest" eingibt.

Dieser Tipp wurde bereits 29.941 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6
(einschl. Beispielprojekt!)

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2014 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.

Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel