VisualBasic .NET - Threads in unterschiedlichen Forms - warten bis beendet

palaber

Captain
Registriert
Juni 2006
Beiträge
3.856
Hallo zusammen,

ich habe noch nicht wirklich viel mit Threads gearbeitet und bin mir nicht sicher ob mein Ansatz eine saubere Sache ist. Bis auf ein Problem geht es so. Evtl. brauch ich aber einen neuen Denkanstoss um das Problem zu beheben. Zunächst einmal zu den Gegebenheiten:

Ich habe eine Form "Form1". In dieser führe ich diversen Code aus. An einer Stelle setzt eine komplexe Berechnung ein, die ich in einen extra Thread "exThread" ausgelagert habe. Direkt nachdem ich den Thread gestartet habe öffne ich eine zweite Form "Form2" als DialogResult. Dies geschieht aus dem Grund, dass der Code auf die Berechnung warten soll und dem User anzeigt, das die Berechnung läuft. Die Form1 soll derweilen für Aktionen des Users gesperrt sein.

In der Form2 läuft wiederrum ein extra Thread "exThread2", der darauf wartet bist aus exThread eine Variable der Form2 auf "True" geändert wurde. Sobald dies der Fall ist gebe ich ein DialogResult zurück.

Anbei mal auszugsweise verinfachter Code um es Darzustellen. Zunächst Form1:
Code:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
    'Diverser Code vor der Berechnung'

    Dim exThread As New Thread(New ThreadStart(AddressOf doWorkOptimizeRoute))
    exThread.IsBackground = True
    exThread.Start()

    Form2 = New Form2
    Form2.ShowDialog()

    'Diverser Code der erst nach der Berechnung ausgeführt werden soll'

End Sub

'Funktion die in einem extra Thread aufgerufen wird'
Sub doWorkOptimizeRoute()
    route.Waypoints.Optimize()   'Berechnung aus MS MapPoint OCX'
    Thread.Sleep(50)
    Form2.stopLoop = True      'Setzt in Form2 Abbruchbedinung für Loop - ist das so zulässig?'
End Sub

Und die Form2 - in der Läuft nur eine Progressbar (Marquee) und es gibt eine Textbox in der eine Info steht:
Code:
Public Class Form2
    Public stopLoop = False    'Ist nicht sauber da Public - aber zu Demozwecken ok ;)'

    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim exThread2 As New Thread(New ThreadStart(AddressOf DoWork))
        exThread2.IsBackground = True
        exThread2.Start()
    End Sub

    'Methode die in extra Thread läuft'
    Private Sub DoWork()
        While Not stopLoop
            'Solange stopLoop nicht aktiviert blockiere Anwendung'
            Thread.Sleep(50)    '50 millisek. Pause'
        End While

        Thread.Sleep(50)
        Me.DialogResult = Windows.Forms.DialogResult.OK 'Wenn Berechnung aus Form1_exThread ferig - schließe Fenster'
    End Sub
End Class

Das Problem: Wenn ich während Form2 geöffnet ist auf Form1 klicke stoppt die Progressbar oder es kommt keine Rückmeldung. Die Berechnung läuft zwar durch, aber für mich ist das nicht wirklich akzeptabel!

Noch eine Frage, wenn ich aus dem UI Thread der Form1 die Form2 öffne, läuft diese dann im UI-Thread der Form1 weiter oder wird für die Form2 ein extra UI-Thread gestartet?
 
Zuletzt bearbeitet:
Bei ShowDialog kannst du als Parameter das Handle des Parent-Fensters (also Form1) übergeben. Dann kannste zur Laufzeit nicht mehr in die Form1 klicken solange Form2 offen ist.

Aber statt "zu Fuß" die Threads zu managen könntest du auch einfach einen Backgroundworker nehmen. Das vereinfacht einiges. Der wirft ein Event wenn er anfängt zu rechnen, man kann ein Progress-Event auslösen und es gibt ein Ende-Event. Müßte eigentlich ideal für Progressbar-Anzeigen sein.
 
Hatte es zunächst mit dem Backgroundworker versucht. Da hat es leider auch nicht so recht geklappt. Dachte ich versuche es mal mit "manuellen" Threads. Das mit dem Handler versuche ich gleich mal aus. Danke!

Hab mal einfach showDialog(Me) eingfügt. Leider stoppt der Fortschritt der Progressbar immernoch wenn ich auf die Form1 klicke...

Edit:
Also die wohl stümperhafteste Lösung die mir eingefallen ist, ist die Form2 zu maximieren. Somit kommt man nicht auf die Form1 und die Form2 freezt nicht. Aber das kann es ja nicht gewesen sein, oder?!? :freak:
 
Zuletzt bearbeitet:
Wenn Form2 wirklich nur dazu gedacht ist, dass der User nichts mehr in Form1 machen kann und eine Art Fortschrittsanzeige haben soll, kannst du in einem einfachen Fall auch einfach Form2.TopMost = true setzen. Das verhindert auch, dass der User Programmteile, die unter Form2 liegen, anklicken kann.

Im WPF Extended Toolkit gibt's für solche Sachen extra einen BusyIndicator. Für WinForms wüsste ich nun keine Entsprechnung. Vielleicht kannst du dir aber etwas ähnliches selbst programmieren.
 
DocWindows schrieb:
@exec84: Kannst bei WinForms den Mauszeiger per Programmcode ganz einfach auf "Sanduhr" setzen :)

Und was machst du, wenn der User mit Alt+TAB das Programmfenstern wechselt und das Programm mit der Tastatur bedient?
 
@palaber
Du willst also mithilfe eines Dialogs dein Hauptfenster vor Nutzereingaben "schützen"?
Und was passiert wenn der Nutzer den Dialog einfach schließt/abschießt?

Warum packst du die Progressbar nicht einfach in dein Hauptfenster und deaktivierst alle anderen Controls (siehe Control.Enabled Property) solange der Hintergrundthread arbeitet?
 
Zurück
Oben