Threads Imports System.Threading (Download File My.Computer.Network.DownloadFile("http://aetos.it.teithe.gr/~asidirop/ADE/_ files/list.txt", "C:\Temp\list.txt") Components Αν βάλουµε πάνω στην φόρµα ένα BackgroundWorker Component µπαίνει στο component tray. [1]
Sequence of events Form s thread Call RunWorkerAsync method ProgressChanged event handler DoWork event handler (work is going on) Background worker s thread To cancel, call CancelAsync method RunWorkerCompleted event handler Check CancellationPending property If not canceled,do work and ReportProgress (work is complete) Εστω ότι έχουµε δυο φόρµες Form1 (Main Thread) και Form2 (Second Form) Θέλουµε όταν γίνεται κλικ το Button1 της Form1 να καλείται 2 ο thread που τρέχει µαζί µε το 1 ο thread BackgroundWorker1.RunWorkerAsync() κάνοντας ότι εργασίες πρέπει να κάνει BackgroundWorker1_DoWork ) Το 2 ο thread αν δεν το σταµατηθεί BackgroundWorker1.CancellationPending µπορεί να δίνει αναφορά στο 1 ο thread για το ποσοστό της εργασίας του BackgroundWorker1.ReportProgress(work) κάθε φορά που αλλάζει η εργασία του BackgroundWorker1_ProgressChanged Το 2 ο thread όταν τελειώσει την δουλειά του BackgroundWorker1_RunWorkerCompleted θα σταµατηθεί µε το BackgroundWorker1.CancelAsync() Στην παρακάτω φόρµα (Μain Thread) πατώντας το κουµπάκι Call 2 nd thread.. καλείται να ανοίξει ασυγχρόνως ένα 2 ο Thread (Second Form), να περιµένει λιγάκι και κατόπιν να κλείσει. [2]
Στην 1 η φόρµα υπάρχει ένα progress bar και στην 2 η µια ετικέτα Στην Form1 (Main Thread) : Imports System.Threading Public Class MainThread Private Sub MainThread_Load(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles MyBase.Load 'Αλλaγή θέση της φόρµας, για να φαίνεται καλύτερα όταν ανοίξει και η 2η φόρµα Me.Location = New System.Drawing.Point(200, 400) Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles Button1.Click Button1.Visible = False 'Καλείται το 2 ο thread BackgroundWorker1.RunWorkerAsync() Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As _ System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork 'H δουλειά το 2 ου thread είναι ΝΑ ΑΝΟΙΞΕΙ ΤΗΝ 2 η ΦΟΡΜΑ 'να κάνει ΟΤΙ ΠΡΕΠΕΙ ΝΑ ΚΑΝΕΙ (π.χ. να µετράει από 1..100) 'και να δίνει ΑΝΑΦΟΡΑ (αν θέλουµε) για το ΤΙ ΚΑΝΕΙ SecondForm.Show() 'Χρονοκαθυστέρηση - έστω εδώ διάφορες λειτουργίες 1..100 (βαριές) και ένα 'sleep για να «φανούν» βαριές For work As Integer = 1 To 100 ' The number of milliseconds for which the thread is blocked. Thread.Sleep(100) BackgroundWorker1.ReportProgress(work) SecondForm.Label1.Text = "Τρέχουσα Λειτουργία: " & work.tostring SecondForm.Refresh() [3]
Next SecondForm.Close() Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object,_ ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles _ BackgroundWorker1.RunWorkerCompleted Button1.Visible = True 'όταν τελειώσει το σταµατάµε BackgroundWorker1.CancelAsync() Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged End Class ProgressBar1.Value = e.progresspercentage 2 η ΑΣΚΗΣΗ 0,0 100,0 Στην φόρµα (Μain Thread) θα µπορούσε να υπάρχει και άλλο ένα κουµπάκι για ακύρωση του 2 ου thread BackgroundWorker1.CancelAsync() Eπίσης θα µπορούσε µέσα στα διάφορα στάδια της εργασίας του 2 ου thread να ελέγχει αν ακυρώνεται If BackgroundWorker1.CancellationPending Then e.cancel = True Form2.Close Exit Sub End If Όπως και στο παράδειγµα components.sln 300 25 Size ProgrBar 300*1/3 = 100 Size TextBox 300*2/3 = 200 100 200 Private Sub EnchancedProgressBar_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SizeChanged Me.ProgressBar1.Location = New System.Drawing.Point(0, 0) Me.ProgressBar1.Size = New System.Drawing.Size(Me.Width * 1 / 3, Me.Height) Me.TextBox1.Location = New System.Drawing.Point(Me.Width * 1 / 3, 0) Me.TextBox1.Size = New System.Drawing.Size(Me.Width * 2 / 3, Me.Height) [4]
Imports System.IO Imports System.Net Imports System.Text Imports System.Text.RegularExpressions Imports System.Threading Public Class EnhancedProgressBar 'Public Property URL() As String 'Public Property SavePath() As String ' Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As _ System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork 'Button1.Visible = True Thread.Sleep(1000) Dim request As WebRequest = WebRequest.Create(Me.URL) request.credentials = CredentialCache.DefaultCredentials Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse) Dim datastream As Stream = response.getresponsestream() ' Open the stream using a StreamReader for easy access. Dim reader As New StreamReader(dataStream) ' compute the filename Dim regfile As Regex = New Regex("(^.*[=\\/?&])") Dim filename = regfile.replace(response.responseuri.absoluteuri.tostring, "") If filename = "" Then filename = "index.html" End If Dim writer As StreamWriter writer = File.CreateText(SavePath & "\\" & filename) ' Dim line As String Dim size As Integer = 0 Dim readbytes As Integer Dim buffer(200) As Char Do readbytes = reader.readblock(buffer, 0, 128) For i = 1 To readbytes writer.write(buffer(i - 1)) Next 'line = reader.readline() size += readbytes 'MsgBox(100.0 * size / response.contentlength) BackgroundWorker1.ReportProgress(100.0 * size / response.contentlength) 'writer.writeline(line) Thread.Sleep(100) Loop Until readbytes = 0 [5]
BackgroundWorker1.ReportProgress(100) ' Cleanup the streams and the response. reader.close() datastream.close() response.close() writer.close() 'Private Sub BackgroundWorker1_ProgressChanged 'Private Sub BackgroundWorker1_RunWorkerCompleted 'Private Sub Button1_Click End Class [6]