Invoke, Delegate, Klasse

  • VB.NET

Es gibt 34 Antworten in diesem Thema. Der letzte Beitrag () ist von petaod.

    Invoke, Delegate, Klasse

    Hi,
    ich habe hier eine Beschreibung gefunden die relative gut erklärt ist.
    Quelle: vcware.de (leider nicht mehr on)

    VB.NET-Quellcode

    1. Public Class Form1
    2. Public Delegate Sub ChangeLabelText(ByVal caption As String)
    3. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    4. Handles Button1.Click
    5. BackgroundWorker1.RunWorkerAsync()
    6. End Sub
    7. Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
    8. ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    9. Me.Invoke(New ChangeLabelText(AddressOf Change), "hallo!")
    10. End Sub
    11. Public Sub Change(ByVal caption As String)
    12. Label1.Text = caption
    13. End Sub
    14. End Class


    Ausschnitte aus der Beschreibung:
    Spoiler anzeigen
    Ein Delegate-Sub zusammen mit der Invoke-Methode ist eine schöne Methode,
    um auf Formelemente und -controls zugreifen zu können.
    Beginnen wir mit einem kleinen Beispiel:
    Ein Label auf der Form soll per Backgroundworker den Text ändern.
    Beginnen wir mit einem modulweit deklarierten Delegate-Sub.

    Das ganze funktioniert also über 3 Komponenten:
    Den Delegate-Sub, den "delegateten" Sub und den Aufruf.
    Leider lässt dieser Code keine variable Zuweisung des Textes zu.

    Daher auch dafür noch ein Beispiel:




    Wie könnte man das in eine Klasse packen ? (DLL)

    Da ich noch nie mit Invoke, Delegate usw... zu tun hatte, komme ich leider nicht weiter.

    Hintergrund:
    Ich möchte kleinere Aktionen auslagern.
    - Einlesen meines FTP Verzeichnise
    - Einlesen der Dateien im ausgewählten Verzeichnis

    Wenn das in einem BackgroundWorker läuft, ist meine Form nicht blockiert.
    Wenn ich das alles richtig gelesen und verstanden habe.

    vielen dank

    Bernd
    Wenn du auf das BackgroundWorker.RunWorkerCompleted Event wartest, dann brauchst du kein Invoke. Invoke macht nur dann Sinn, wenn du etwas wirklich "per Hand" in einen anderen THREAD auslagerst. BackgroundWorker ist extra dafür gedacht, um dies NICHT tun zu müssen. Siehe msdn.microsoft.com/en-us/libra…del.backgroundworker.aspx

    Dafür sind BW aber langsamer als normale Threads. Aber da müsstest du dich halt um sowas kümmern.
    OK ich erkläre es anders,
    vielleicht ist ja deine Antwort das was ich mache möchte ? Nur verstehe ich sie leider nicht.

    Was ist ein Delegate ?
    Was ist ein Invoke ?

    (bitte keine Links zu msdn, die finde ich selber)

    Ich möchte z.B. in einer ListBox alle Verzeichnissen auflisten.
    Die ListBox befindet sich im Aktuellen Projekt und in Form1.

    Als nächstest möchte ich alle Dateien in in einer ListBox aufgelistet haben.
    Die ListBox befindet sich ebenfalls in Form1.

    Der ganze Ablauf soll halt so ablaufen, das meine Form nicht stehen bleibt. (einfriert)

    Soviel habe ich schon verstanden:

    - Auslagern in einen Separaten Thread, damit Form1 weiter läuft.
    - Rückgaben an Form1 solten man über Delegate, oder Invoke oder .... machen.

    Einen BackGroundWorker, starte ich aber in Form1 , oder ?
    Läuft dann die Form weiter ?



    Also anders,
    Schritt für Schritt. Wer ist für was ?


    Danke

    Bernd
    Ein Delegat ist eine Variable, die einen Verweis auf eine Funktion speichert.
    Beispiel:

    VB.NET-Quellcode

    1. Public Class FormDelegateTest
    2. Public Delegate Sub SaySomethingDelegate()
    3. Public SaySomething As SaySomethingDelegate
    4. Public Sub SayHi()
    5. MessageBox.Show("Hi.")
    6. End Sub
    7. Public Sub SayBye()
    8. MessageBox.Show("Bye.")
    9. End Sub
    10. Private Sub ButtonSayHi_Click(...) Handles ButtonSayHi.Click
    11. SaySomething = AddressOf SayHi
    12. ' Alternativ:
    13. ' SaySomething = New SaySomethingDelegate(AddressOf SayHi)
    14. End Sub
    15. Private Sub ButtonSayBye_Click(...) Handles ButtonSayBye.Click
    16. SaySomething = AddressOf SayBye
    17. ' Alternativ:
    18. ' SaySomething = New SaySomethingDelegate(AddressOf SayBye)
    19. End Sub
    20. Private Sub ButtonSaySomething_Click(...) Handles ButtonSaySomething.Click
    21. SaySomething.Invoke()
    22. ' Alternativ:
    23. ' SaySomething()
    24. End Sub
    25. End Class
    Bei diesem Code wird entweder SayHi() oder SayBye() beim Klick auf den Button "ButtonSaySomething" ausgeführt.
    Hat man zuvor auf ButtonSayHi geklickt, wird SayHi() ausgeführt, und hat man zuvor auf den ButtonSayBye geklickt, wird SayBye() ausgeführt.
    Hat man auf keinen Button geklickt, wird höchstwahrscheinlich eine Fehlermeldung geworfen.


    Gute Erklärung: codeproject.com/KB/vb/Delegate.aspx

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „haiyyu“ ()

    haiyyu schrieb:

    Ein Delegat ist eine Variable, die einen Verweis auf eine Funktion speichert.

    Das ist mal eine Einfache und gute Erklärung!

    Kann man hier eigentlich 2 x auf Hilfreich drücken ?


    Ich schaue mir dein Beispiel heute Abend mal in ruhe an.
    Bastel einige Versuche.
    Ich denke damit komme ich klar.

    Edit:
    wollte auf Vorschau nicht auf Absenden klicken.

    Vielen Dank

    Bernd

    Edit:

    Ok was heist denn das Invoke ?

    VB.NET-Quellcode

    1. SaySomething.Invoke()

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bernd“ ()

    Invoke heißt "aufrufen". Invoke bewikt, dass die Methode, auf den der Delegat zeigt, aufgerufen wird. Das nutzt man z.B. dann, wenn man eine Steuerlementeigenschaft im Kontext des GUI-Threads setzen will (per Control.Invoke(Delegate m) Aber wie gesagt das braucht man nicht bei BackgroundWorkern.
    OK,
    ich versuche es so zu beschreiben.

    Ich möchte in einem Extra Thread Daten einsammeln.
    Wenn der Thread durchgelaufen ist, sollen die eingesammelten Daten in einer ListBox oder ähnlichem angezeigt werden.
    Also dann in Form1 natürlich.

    Ich bin nun den dritten Tag unterwegs um ein Funktionierendes Beispiel zu finden.
    Selbst bei MSDN sind nur Bruchteile oder fehlerhafte Beispiele vorhanden.

    Kenn jemand ein schönes Beispiel, welches auch Funktioniert ?


    vielen dank

    Bernd
    Vom Prinzip ja erstmal egal.

    Aber es sind Daten Verzeichnisse vom FTP bzw. dann ja auch Files die in den Daten Verzeichnisse liegen.

    Es könnten aber vom Prinzip auch Daten aus meiner Daten Bank sein.


    PS
    habe gerade ein Beispiel bei msdn gefunden. Hammer. Der Produzier ein leeres Form.
    So nen Scheiß produzieren und veröffentlichen die.
    Meinste den: msdn.microsoft.com/de-de/libra…del.backgroundworker.aspx

    Ja da musst du erst das Form selbst erstellen. Die erwarten schon, dass man die Erklärung liest:

    Um diesen Code auszuprobieren, erstellen Sie eine Windows Forms-Anwendung. Fügen Sie ein Label-Steuerelement mit dem Namen resultLabel und zwei Button-Steuerelemente mit den Namen startAsyncButton und cancelAsyncButton hinzu. Erstellen Sie Click-Ereignishandler für beide Schaltflächen. Fügen Sie aus der Registerkarte Komponenten der Toolbox eine BackgroundWorker-Komponente namens backgroundWorker1 hinzu. Erstellen Sie die Ereignishandler DoWork, ProgressChanged und RunWorkerCompleted für den BackgroundWorker. Ersetzen Sie im Code des Formulars den vorhandenen durch den folgenden Code.


    Sonst ist das Beispiel wirklich top!


    EDIT: Das zweite Beispiel funktioniert auch so!
    So das Beispiel welches du nun gepostet hast geht.

    Jetzt käme der nächste schritt.
    Wie bekommt man aus der Funktion eine List(Of zurück)

    Ich habe natürlich eine andere Function

    VB.NET-Quellcode

    1. Private Function FTP_Verzeichnisse_Auslesen(ByVal n As Integer, _
    2. ByVal worker As BackgroundWorker, _
    3. ByVal e As DoWorkEventArgs) As List(Of String)
    4. Dim MeineListe As New List(Of String)
    5. Dim request As Net.FtpWebRequest = CType(Net.FtpWebRequest.Create(FTP_Server), FtpWebRequest)
    6. 'request.Method = Net.WebRequestMethods.Ftp.ListDirectory
    7. request.Method = Net.WebRequestMethods.Ftp.ListDirectoryDetails
    8. request.Credentials = New Net.NetworkCredential(FTP_User, FTP_Passw)
    9. Try
    10. Dim response As Net.FtpWebResponse = CType(request.GetResponse(), FtpWebResponse)
    11. Using myReader As New System.IO.StreamReader(response.GetResponseStream())
    12. Do While myReader.EndOfStream = False
    13. Dim Auswerten As String = myReader.ReadLine()
    14. If Auswerten.StartsWith("d") Then
    15. If Not Auswerten.EndsWith(".") And Not Auswerten.EndsWith("..") Then
    16. Dim LasIndexOf As Integer = Auswerten.LastIndexOf(" ")
    17. Dim NeuerEintrag As String = Auswerten.Substring(LasIndexOf)
    18. MeineListe.Add(Trim(NeuerEintrag))
    19. End If
    20. End If
    21. Loop
    22. End Using
    23. Catch ex As Exception
    24. MessageBox.Show(ex.Message & vbNewLine & "FTP_Verzeichnisse_Auslesen_Click()")
    25. End Try
    26. Return MeineListe
    27. End Function
    So:

    VB.NET-Quellcode

    1. Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    2. Dim MeineListe As New List(Of String)
    3. Dim request As Net.FtpWebRequest = CType(Net.FtpWebRequest.Create("server.server.server"), FtpWebRequest)
    4. 'request.Method = Net.WebRequestMethods.Ftp.ListDirectory
    5. request.Method = Net.WebRequestMethods.Ftp.ListDirectoryDetails
    6. request.Credentials = New Net.NetworkCredential("user", "password")
    7. Try
    8. Dim response As Net.FtpWebResponse = CType(request.GetResponse(), FtpWebResponse)
    9. Using myReader As New System.IO.StreamReader(response.GetResponseStream())
    10. Do While myReader.EndOfStream = False
    11. Dim Auswerten As String = myReader.ReadLine()
    12. If Auswerten.StartsWith("d") Then
    13. If Not Auswerten.EndsWith(".") And Not Auswerten.EndsWith("..") Then
    14. Dim LasIndexOf As Integer = Auswerten.LastIndexOf(" ")
    15. Dim NeuerEintrag As String = Auswerten.Substring(LasIndexOf)
    16. MeineListe.Add(Trim(NeuerEintrag))
    17. End If
    18. End If
    19. Loop
    20. End Using
    21. Catch ex As Exception
    22. MessageBox.Show(ex.Message & vbNewLine & "FTP_Verzeichnisse_Auslesen_Click()")
    23. End Try
    24. e.Result = MeineListe
    25. End Sub


    Und im DoWork-Event enthält ebenfalls e.Result die Liste
    Ups,
    ein Dickes Fettes Lob und danke.

    Soweit bin ich jetzt auch.
    Im BackGroundWorker eine ListOf erstellen und an e weitergeben.

    Nun versuche ich das ganze in eine Klasse (DLL) auzulagern.
    Und genau das war meine Frage in Post 1
    Wie könnte man das in eine Klasse packen ? (DLL)


    Ich möchte den BGW in einer anderen Klasse haben.
    Damit zum Schluß nur noch folgendes Übrig bleibt.
    ca.

    VB.NET-Quellcode

    1. ListBox1.Items.AddRange(DLL.Klasse.Verzeichnisse_Lesen(FTP_Pfad, User, Passwort).ToArry


    ich bastel mal weiter, vielleicht komme ich noch dahinter.

    Nochmals Lieben dank
    Bernd

    PS
    soll ne kleine FTP Lib für meinen Hausgebrauch werden
    He Mike,

    da ich leider mit Thread übergreifenden Sachen noch nie gearbeitet habe, fällt mir das ganze noch etwas schwer.
    Vermutlich weil ich nicht ganz den Durchblick bekomme.
    - Delegate
    - Invoke
    - Thread
    - BackGroundWorker
    und der ganze kram den dann so beim lesen noch auftaucht.
    Puh, da habe ich mir ein neues Thema ausgesucht. Naja, muss ich durch.

    Ok das ganze in eine Klasse auslagern, war ja auch meine Idee.
    Nur habe ich es bisher nicht geschafft , trehadübergreifend das Ergebnis zurück zu liefern.

    Ich versuche da ganze mal mit einer Klasse.
    Zur not mit einer Property List(Of


    vielen dank für deinen Denkanstoß

    Bernd
    Achso. Ich dachte du wills die Property aus DoWork anprechen. Ja das geht dann schon ,aber das Problem bei der ganzen sache ist, dass du nicht weißt, wann DoWork fertig ist....
    Aber eigentlich, von meinem denken her.
    Wenn ich den ganzen kram mit BGW in eine Klasse auslager,
    inkl. BGW_DoWork, BGW_ProgressChanged und BGW_RunWorkerCompleted
    bekommt doch der Completed das mit.

    Dann noch halt die ermittelten Daten/Werte zurück ins Mainthread.

    Ups, und dann gehts bei mir los.