Visual Basic Forum

Visual Basic Forum
für VB6 und VB.NET Programmierer
 
RegistrierenRegistrieren  LoginLogin

Neues Thema eröffnen   Neue Antwort erstellen    Visual Basic Forum Foren-Übersicht -> [VB.NET] Tipps & Tricks
Autor
Nachricht
^^kev####
Überflieger
Überflieger

Anmeldedatum: 01.05.2008
Beiträge: 476
Wohnort: Haan

Multithreading mit VB.NET 2005
Verfasst am: 29.06.2009, 15:15

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:
Visual Basic: [code]Imports System.IO
Imports System.ComponentModel[/code]

Private Variablen:
Visual Basic: [code]' unser Thread
Private th As BackgroundWorker

' wieviele Bytes wurden kopiert
Private lngBytesCopied As Long

' Die Speicheradresse der Zieldatei
Private lngSourceFileLength As Long[/code]

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

Visual Basic: [code]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 = ""
Me.lblTarget.Text = ""
Me.cmdCopyAsync.Enabled = False
Me.cmdCancel.Enabled = False
Me.progress.Visible = False
Me.lblProgress.Visible = False
End Sub[/code]

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

Visual Basic: [code]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
[/code]

Visual Basic: [code]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[/code]

Hier wird der asnchrone Thread gestartet:
Visual Basic: [code]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[/code]

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

Visual Basic: [code]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[/code]

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.

Visual Basic: [code]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[/code]

Die Cancel-Operation:

Visual Basic: [code]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[/code]

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

Visual Basic: [code]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[/code]

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

Visual Basic: [code]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[/code]

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

Quelle: vbarchiv.net
_________________
 
Neues Thema eröffnen   Neue Antwort erstellen    Visual Basic Forum Foren-Übersicht -> [VB.NET] Tipps & Tricks

Tags: visual basic, multithreading, thread, 2005

 
 Verwandte Themen   Aufrufe   Letzter Beitrag 
Keine neuen Beiträge Wichtig: [Ebook] jetzt lerne ich Visual Basic 6 2987 02.06.2010, 13:55
Keine neuen Beiträge Miceosoft Visual Basic 6.0 Einsteiger Kurs? 716 17.02.2007, 21:01
Keine neuen Beiträge SUCHE MICROSOFT VISUAL BASIC! 516 12.02.2007, 21:54
Keine neuen Beiträge Microsoft Visual Basic 793 28.01.2007, 00:59
Keine neuen Beiträge Visual Basic.. Version?? 764 22.01.2007, 18:23
 



[ Time: 0.3261s ][ Queries: 81 (0.1243s) ][ GZIP on - Debug on ]