Frage

Ich bin für eine generische Methode einer Warte Bildschirm bei langen Operationen zu implementieren. Ich habe vor dem Einfädeln ein paar Mal benutzt, aber ich habe das Gefühl, dass ich es umgesetzt entweder sehr schlecht oder mit viel zu viel Aufwand (und Kopieren / Einfügen - der Horror).

Ich möchte dies als generisch halten und einfach wie möglich, so dass ich nicht haben, um Lasten von BackgroundWorkers zu implementieren alle Arten von Mist Handhabung, die Dinge schwer zu halten.

Hier ist, was ich tun möchte - bitte beachten Sie, diese von unterschiedlich sein können, was tatsächlich möglich / Best Practice / was auch immer - mit VB.NET, Framework 2.0 (also keine anonymen Methoden):

  Private Sub HandleBtnClick(sender as Object, e as EventArgs) Handles Button.Click
      LoadingScreen.Show()

      'Do stuff here, this takes a while!'
      Dim Result as Object = DoSomethingTakingALongTime(SomeControl.SelectedObject)

      LoadingScreen.Hide()

      ProcessResults(Result)
  End Sub

Die Anwendung ist nun vollständig single-threaded, so läuft alles auf dem GUI-Thread. Ich muss in der Lage, Objekte in DoSomethingTakingALongTime() zuzugreifen, ohne Cross-Thread Ausnahmen zu bekommen. Der GUI-Thread wartet auf ein bestimmtes Verfahren (das eine lange Zeit in Anspruch nimmt) in Anspruch nehmen, während das LoadingScreen Formular ansprechbar bleiben sollte (es ist animiert / hat ein progressbar / etc.).

Ist das ein doable / guter Ansatz oder sehe ich auf diese Weise zu einfach? Was ist die beste Praxis diesbezüglich? Und vor allem: Wie konnte ich ein solches System implementieren? Wie ich bereits erwähnt, habe ich sehr wenig Erfahrung mit einem Gewinde, so sanft bitte: -)

War es hilfreich?

Lösung

Ihr Problem ist, dass Ihr einen Querfaden Ausnahme bekommen, wenn Ihr versucht, Ihre Worker-Thread Daten auf Ihren UI-Thread zu übergeben. was Sie tun müssen, ist InvokeRequired zu überprüfen und BeginInvoke bevor die Bedienelemente des ui einstellen, so dass Sie wie so nicht den Fehler:

Private Sub work_CrossThreadEvent(ByVal sender As Object, ByVal e As System.EventArgs) Handles work.CrossThreadEvent

       If Me.InvokeRequired Then
           Me.BeginInvoke(New EventHandler(AddressOf work_CrossThreadEvent), New Object() {sender, e})
           Return
       End If

      Me.Text = "Cross Thread"

End Sub

nur den New EventHandler Teil an den Event-Handler ändern Ihre Verwendung.

Auch denke ich mit einem Hintergrund Arbeiter ist keine schlechte Methode für Ihre Arbeiter Klassen, nur eine Klasse für Ihre Arbeit schaffen und den Hintergrund Arbeiter verwenden das Einfädeln Sachen ein bisschen wie dies zu tun:

Public MustInherit Class Worker

    Protected WithEvents worker As BackgroundWorker

    Public Sub New()

        worker = New BackgroundWorker()
        worker.WorkerReportsProgress = True
        worker.WorkerSupportsCancellation = True

    End Sub

    Public Sub Start()

        If (Not worker.IsBusy AndAlso Not worker.CancellationPending) Then
            worker.RunWorkerAsync()
        End If

    End Sub

    Public Sub Cancel()
        If (worker.IsBusy AndAlso Not worker.CancellationPending) Then
            worker.CancelAsync()
        End If
    End Sub

    Protected MustOverride Sub Work()

    Private Sub OnDoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
        Work()
    End Sub

    Public Event WorkCompelted As RunWorkerCompletedEventHandler
    Private Sub OnRunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
        OnRunWorkerCompleted(e)
    End Sub
    Protected Overridable Sub OnRunWorkerCompleted(ByVal e As RunWorkerCompletedEventArgs)
        RaiseEvent WorkCompelted(Me, e)
    End Sub

    Public Event ProgressChanged As ProgressChangedEventHandler
    Private Sub OnProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles worker.ProgressChanged
        OnProgressChanged(e)
    End Sub
    Protected Overridable Sub OnProgressChanged(ByVal e As ProgressChangedEventArgs)
        RaiseEvent ProgressChanged(Me, e)
    End Sub

End Class

Public Class ActualWork
    Inherits Worker

    Public Event CrossThreadEvent As EventHandler

    Protected Overrides Sub Work()

        'do work here'
        WorkABit()
        worker.ReportProgress(25)

        WorkABit()
        worker.ReportProgress(50)

        WorkABit()
        worker.ReportProgress(75)

        WorkABit()
        worker.ReportProgress(100)

    End Sub

    Private Sub WorkABit()

        If worker.CancellationPending Then Return
        Thread.Sleep(1000)
        RaiseEvent CrossThreadEvent(Me, EventArgs.Empty)

    End Sub

End Class

Disclaimer .. etwas verrostet mit vb, aber Sie sollten die Idee.

Andere Tipps

In dem Thread verwenden Application.Run (yourform) zu bekommen, was Sie wollen.

Beachten Sie, dass Sie benötigen, um das Formular zu signalisieren, sich zu schließen, irgendwie.

Ich hoffe, dass Sie nicht finden, diese nicht hilfreich - aber ich würde fragen, warum Sie einen Gewindewarte Bildschirm wollen würden? Der Grund für die in erster Linie mit Gewinde ist, so dass der UI ansprechbar bleibt und lange Operationen werden im Hintergrund durchgeführt.

Ansonsten könnte man genauso gut haben nur eine ProgressBar auf FormLoading Kontrolle und haben DoSomethingTakingALongTime sie in regelmäßigen Abständen zu aktualisieren. Dies würde nicht Threads braucht überhaupt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top