Backgroundworker über Timer aufrufen

  • VB.NET

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von vivil.

    Backgroundworker über Timer aufrufen

    Hallo Forum,

    ich lese über ein Kartenlesegerät die eGK und die KVK korrekt aus.
    Nun überprüfe ich mit einem Timer alle 3 Sekunden, ob eine Karte eingesteckt ist oder nicht.
    Da die Befehle an die Karte und deren Rückgabewerte aber alle insgesamt ca. 1-3 Sekunden dauern, hängt sich meine Form für
    diese Zeit auf.

    Nun möchte ich über den Backgroundworker in der Methode doWork die Daten bzw. die Befehle an die Karte auslesen lassen.
    Der Timer ruft die startet den Backgroundworker so:

    VB.NET-Quellcode

    1. Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    2. If Not bgwTimer.IsBusy Then
    3. bgwTimer.RunWorkerAsync()
    4. ElseIf bgwTimer.IsBusy Then
    5. bgwTimer.CancelAsync()
    6. End If
    7. End Sub


    Nun ist mein Problem, dass ich eine Fehlermeldung bekomme, wenn ich einen Button.Enabled = True setzten will:
    Ungültiger threadübergreifender Vorgang: Das Steuerelement.....


    Ich glaube das es daran liegt, das nach jedem Befehl an die Karte ein .invoke eingesetzt werden muss.

    Stimmt das oder liege ich da falsch ?


    vivil


    Edit by Manschula: Die Farbe Rot ist der Moderation vorbehalten --> Kolorierung entfernt, Fehlermeldung als Zitat eingefügt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Manschula“ ()

    Du musst alle Aufrufe an GUI-Komponenten, die du aus dem Worker-Thread machst, per Invoke aufrufen. Soll das ganze am Ende vom Worker-Thread geschehen, kannst du das entsprechende Event dafür verwenden, welches automatisch im GUI-Thread läuft.

    - Phil.
    Was sind denn alles GUI-Elemente ? Kenne mich damit 0 aus.
    Ich weiß das Textboxen, Labels, Buttons usw. Elemente sind, aber was denn noch ?
    Und wie sehen die Aufrufe mit Invoke aus, so in etwa:

    VB.NET-Quellcode

    1. btAnlegen.Invoke(New UpdateTextHandler(AddressOf Anmeldung.UpdateControl))


    Und die dazugehörige Funktion:

    VB.NET-Quellcode

    1. Private Delegate Sub UpdateTextHandler(ByVal MyControl As Control)


    Und was hier passieren soll:

    VB.NET-Quellcode

    1. Private Shared Sub UpdateControl(ByVal MyControl As Control)
    2. Throw New NotImplementedException
    3. Anmeldung.btAnlegen.Enabled = True
    4. End Sub
    iwie greifst du aus dem Nebenthread auf iwelche Controls zu, und das geht nicht.
    Du kannst jetzt diese Zugriffe per Control.Invoke in den Hauptthread delegieren - dann kannst du aber das Gefummel mittm Backgroundworker auch gleich bleiben lassen.

    Ich empfehle also: Lass den Kram mittm Backgroundworker bleiben und tu, was zu tun ist im Timer_Tick-Event, denn dieses läuft per se im HauptThread.
    Diese Timer1_Tick-Herangehensweise ist absolute Grütze.
    Starten meinetwegen.
    Aber wenn Du einen Thread im Timer abbrechen musst, haste gründlich was sowohl nicht verstanden als auch verbockt geproggt.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    ErfinderDesRades schrieb:

    iwie greifst du aus dem Nebenthread auf iwelche Controls zu, und das geht nicht.
    Du kannst jetzt diese Zugriffe per Control.Invoke in den Hauptthread delegieren - dann kannst du aber das Gefummel mittm Backgroundworker auch gleich bleiben lassen.

    Ich empfehle also: Lass den Kram mittm Backgroundworker bleiben und tu, was zu tun ist im Timer_Tick-Event, denn dieses läuft per se im HauptThread.
    Das will ich ja nicht machen, da sonst meine Form hängt !



    RodFromGermany schrieb:

    Diese Timer1_Tick-Herangehensweise ist absolute Grütze.
    Starten meinetwegen.
    Aber wenn Du einen Thread im Timer abbrechen musst, haste gründlich was sowohl nicht verstanden als auch verbockt geproggt.
    Der Timer soll nur alle 3 Sekunden starten und RunworkerAsync() aufrufen, damit mein backgroundworker jedes mal nachschaut ob eine Karte vorhanden ist oder nicht. Wenn eine vorhanden ist, diese auslesen und nachschauen ob die Person schon vorhanden ist, wenn nicht, dann btnAnlegen.Enabled = True, um neue Person anzulegen, wenn diese Person schon vorhanden ist, dann wähle diese im datagrid aus.

    vivil schrieb:

    Der Timer soll nur alle 3 Sekunden starten und RunworkerAsync() aufrufen, damit mein backgroundworker jedes mal nachschaut ob eine Karte vorhanden ist oder nicht.
    Dann kannst Du doch gleich im Timer selbst nachschauen oder dauert das so lange?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ja, meine Form hängt dann kurz und das ist nicht gut, denn wenn keine Karte eingesteckt ist, sucht man nach "Nachname" oder "Vorname"
    und eine Funktion von mir Filtert dann danach. Deswegen will ich das auslesen der Karte im Hintergrund laufen lassen, damit meine Form nicht hängt.


    Edit by Manschula: Warum voll zitieren, wenn der Zitierte direkt über dir steht? --> Unnötiges Vollzitat entfernt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Manschula“ ()

    OK.
    Dann sieh nach, ob der BGW noch arbeitet, und wenn ja, tue einfach gar nichts und warte bis zum nächsten Tick.
    Oder Du vergrößerst das Intervall so, dass der BGW sicher wieder frei ist.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich denke das wird das Problem nicht lösen, da ich nach dem auslesen der Karte nachschaue ob eine Person schon da ist oder nicht, wenn diese noch nicht da ist, btAnlegen.Enabled = True, dann soll der Timer stoppen und weitermachen, wenn die neue Form geschlossen wird ! Wenn man auf den btAnlegen klickt, öffnet sich nämlich ein neues Fenster, wo alle Daten ausgelesen werden und diese werden dann ich einer Datenbank gespeichert. Danach wird die Form geschlossen und die aktuelle Person wird im datagrid ausgewählt.
    Wenn diese Person aber schon vorhanden ist, soll er die aktuelle Person auswählen die ausgelesen wurde. Das hat auch alles vorher mit dem Timer funktioniert, nur dann hat das Fenster immer gehangen und jetzt will ich die Anwendung im Hintergrund laufen lasse, sodass das Fenster nicht mehr hängt.


    Edit by Manschula: Warum voll zitieren, wenn der Zitierte direkt über dir steht? --> Unnötiges Vollzitat entfernt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Manschula“ ()

    vivil schrieb:

    da ich nach dem auslesen der Karte nachschaue ob
    und und und und und.
    Das sieht mir sehr nach Spagetti-Code aus.
    Strukturiere mal Deinen gesamten Programmablauf so, dass Du ihn verstehen und einem dritten erklären kannst.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    vivil schrieb:

    Hallo Forum,

    ich lese über ein Kartenlesegerät die eGK und die KVK korrekt aus.
    Nun überprüfe ich mit einem Timer alle 3 Sekunden, ob eine Karte eingesteckt ist oder nicht.
    Da die Befehle an die Karte und deren Rückgabewerte aber alle insgesamt ca. 1-3 Sekunden dauern, hängt sich meine Form für
    diese Zeit auf.

    Nun möchte ich über den Backgroundworker in der Methode doWork die Daten bzw. die Befehle an die Karte auslesen lassen.

    Ich denke das sagt schon alles aus, zudem muss man sagen, wenn neue person btnanlegen klicken neue Person speichern. Wenn alte Person wähle diese im Datagrid aus.

    Wenn man das nicht versteht, dann weiß ich es auch nicht...

    vivil schrieb:

    Ich denke das sagt schon alles aus
    Fein.
    Dann tue es doch einfach. :thumbsup:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    :D
    Ja, nur ich bekomm ne Fehlermeldung:

    Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement btAnlegen erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.

    Das ist meine Fehlermeldung. Und ich weiß nicht was ich machen muss, damit ich die weg bekomme.


    Edit by Manschula: Warum voll zitieren, wenn der Zitierte direkt über dir steht? --> Unnötiges Vollzitat entfernt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Manschula“ ()

    Wie sieht denn diese Codezeile genau aus?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Quellcode

    1. btAnlegen.Enabled = True


    Genau in dieser Zeile springt er in die exception rein.
    Der Code steht in der Funktion:

    Quellcode

    1. Private Sub bgwTimer_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwTimer.DoWork
    2. End Sub


    Edit by Manschula: Warum voll zitieren, wenn der Zitierte direkt über dir steht? --> Unnötiges Vollzitat entfernt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Manschula“ ()

    vivil schrieb:

    Ungültiger threadübergreifender Vorgang
    Das Zauberwort heißt Invoke.
    Jetzt wollen wir mal hoffen, dass Du mindestens über ein 2010er Studio verfügst, ansonsten musste mal die alte Syntax recherchieren.
    Probier es mal so:

    VB.NET-Quellcode

    1. Me.Invoke(Sub() btAnlegen.Enabled = True)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ahh Super !
    Vielen Dank für die Antwort, es funktioniert jetzt einwandfrei ! :)

    Könntest du mir noch erklären warum man Sub() angeben muss und danach kein komma setzten muss ?

    vivil


    Edit by Manschula: Warum voll zitieren, wenn der Zitierte direkt über dir steht? --> Unnötiges Vollzitat entfernt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Manschula“ ()

    Das wäre natürlich leichter, aber diesen Timer habe ich nicht.
    Ich wollte ihn mit:

    Quellcode

    1. Friend WithEvents Timer3 As System.Windows.Forms.Timers.Timer


    erstellen, doch den gibt es nicht. Ich habe Visual Studio 2010 !


    Edit: Habe es schon gefunden, werde es damit auch mal versuchen.

    Danke !


    Edit by Manschula: Warum voll zitieren, wenn der Zitierte direkt über dir steht? --> Unnötiges Vollzitat entfernt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Manschula“ ()