Handler eines UserControls entfernen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Handler eines UserControls entfernen

    Hallo, innerhalb eines UserControl werden mittels 'AddHandler' Handler erstellt.
    Werden diese Handler automatisch entfernt beim Entfernen des UserControls mit .Dispose() aus dem ParentForm heraus oder muss ich das in einer

    VB.NET-Quellcode

    1. Private Sub UserControleDisposed() Handles Me.Disposed


    im UserControl manuell erledigen?
    @roepke Ggf. kommt es da zu einem Memory-Leak, was aber erst bei gehäuftem Auftreten spürbae wird.
    In welcher Klasse ist denn der Handler zugewiesen?
    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!

    roepke schrieb:

    innerhalb eines UserControl werden mittels 'AddHandler' Handler erstellt.


    ErfinderDesRades schrieb:

    jo, musste selbst aufräumen im Dispose


    roepke schrieb:

    Was passiert wenn ich das nicht mache?
    Dann wird der Handler ggfs. auch dann aufgerufen, wenn das UserControl bereits disposed ist.
    Was im einzelnen dabei passiert steht natürlich in genau dem Handler, den du geadded hast.
    Wenn da etwa Zugriffe auf Controls des UserControls drin vorkommen, wirds Exceptions geben - denn die Controls sind ja disposed.
    @roepke Kannst Du mal relevanten Code posten?
    Ich würde das gern mal exerzieren.
    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!
    Ist eigentlich relativ einfach. Die Händler einfach abbestellen, dann ist alles gut
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @RodFromGermany

    VB.NET-Quellcode

    1. 'Mein UserControl
    2. Public Class uc_SPI_ADC_Module_03_00
    3. Dim frmParentForm As New Form
    4. Private Sub LoadThisUserControl_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
    5. frmParentForm = ParentForm
    6. Call AddHandlers()
    7. End Sub
    8. Private Sub UserControleDisposed() Handles Me.Disposed
    9. Call RemoveHandlers()
    10. End Sub
    11. Private Sub AddHandlers()
    12. Dim _handler As EventHandler = Sub(sender, e) mod_Functions_ControlContentOrIndexChanged(sender, e, frmParentForm ) 'Lambda-Ausdruck
    13. AddHandler GenericPCAClass.GenericPCAClass_evt_ForwardReadFSPData, AddressOf EvaluateResponseOfReadFSPxx_Event
    14. For Each uc_ctrl As Control In Me.Controls
    15. 'Ordnet einem TextBox-Steuerelement-Ereignishandler zur Laufzeit ein Ereignis zu -> Aufruf von 'mod_Functions_ControlContentOrIndexChanged'
    16. If TypeOf uc_ctrl Is TextBox Then
    17. AddHandler uc_ctrl.TextChanged, _handler
    18. End If
    19. Next
    20. End Sub
    21. Private Sub RemoveHandlers()
    22. 'Hier 'frmParentForm' verwenden anstatt 'ParentForm', da durch Dispose diese Info mitunter schon verloren ist.
    23. Dim _handler As EventHandler = Sub(sender, e) mod_Functions_ControlContentOrIndexChanged(sender, e, frmParentForm ) 'Lambda-Ausdruck
    24. RemoveHandler GenericPCAClass.GenericPCAClass_evt_ForwardReadFSPData, AddressOf EvaluateResponseOfReadFSPxx_Event
    25. For Each uc_ctrl As Control In Me.Controls
    26. 'Handler aus AddHandlers weider entfernen
    27. If TypeOf uc_ctrl Is TextBox Then
    28. RemoveHandler uc_ctrl.TextChanged, _handler
    29. End If
    30. Next
    31. End Sub
    32. End Class
    33. Module mod_Functions
    34. Friend Sub mod_Functions_ControlContentOrIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs, frmActiveForm As Form)
    35. If TypeOf sender Is Control Then
    36. Dim ctrl As Control = DirectCast(sender, Control)
    37. If Not TypeOf ctrl Is CheckBox Then 'CheckBoxen Hintergründe werden NICHT geändert
    38. ctrl.BackColor = ProjectWideConstants.cColorBackChanged
    39. End If
    40. Call mod_Functions_SetAsteriskInFormTitelText(frmActiveForm, True) 'Setzt das '*' im Titel des 'frmActiveForm'
    41. End If
    42. End Sub
    43. End Module

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „roepke“ ()

    @roepke Was steht da noch so im Design-Code?
    Z.B. das Base-Control.
    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!
    @roepke
    Call sollte man (nahezu) gar nicht mehr verwenden. Einfach weglassen.

    VB.NET-Quellcode

    1. Dim frmParentForm As New Form
    2. Private Sub LoadThisUserControl_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
    3. frmParentForm = ParentForm
    Wat? Wo soll denn da was angezeigt werden?

    Dein AddHandler/RemoveHandler-Vorgehen dürfte für das RemoveHandler scheitern. Du musst dieselbe Methode adden/removen, nicht die gleiche. Aber Deine Lambdas sind inhaltlich nur gleich, nicht dieselben. Die entstehenden Folgen aus diesem Vorgehen sind unklar. Wahrscheinlich werden die EventHandler später ungewollt weiter ausgeführt.

    VB.NET-Quellcode

    1. For Each uc_ctrl As Control In Me.Controls
    2. 'Handler aus AddHandlers weider entfernen
    3. If TypeOf uc_ctrl Is TextBox Then
    ->

    VB.NET-Quellcode

    1. For Each uc_ctrl As Control In Me.Controls.OfType(Of TextBox)
    2. 'Handler aus AddHandlers weider entfernen

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @RodFromGermany Das ParentForm ist ziemlich umfangreich. Es beinhaltet im wesentlichen ein TabControl mit 11 TabPages. Auf 4 davon kann mittels ComboBox eines von (zur Zeit) 2 UserControl ausgewäht werden, welches dann auf dieser TabPage erscheint. Die Codeschnippsel oben sind stark zusammengekürzt. Die Parentklasse hat über 5000 Zeilen Code, der Designer knapp 4500, das ganze Projekt ist seit Jahren gewachsen und einige MB groß. Mit zig Klassen und Forms. Da ist es schwierig einen bestimmten teil zu extrahieren.

    roepke schrieb:

    ParentForm
    vs

    RodFromGermany schrieb:

    Base-Control.
    Inherits WHAT_EVER.
    Der Inhalt von MY_CONTROL.Designer.vb
    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!
    @VaporiZed Ich nutze 'Call' gerne um klar zu machen, dass ich keine Returnwert erwarte. Ich weiß, dass 'Call' mittlerweile angemeckert wird, aber gibt es triftige Gründe dagegen?
    Hast recht, ich habe meinen Code in Bezug auf den _handler umgeschrieben.

    VB.NET-Quellcode

    1. Public Class uc_SPI_ADC_Module_03_00
    2. Dim frmParentForm As New Form
    3. Dim _handler As EventHandler = Sub(sender, e) mod_Functions_ControlContentOrIndexChanged(sender, e, frmParentForm ) 'Lambda-Ausdruck
    4. Private Sub AddHandlers()
    5. AddHandler GenericPCAClass.GenericPCAClass_evt_ForwardReadFSPData, AddressOf EvaluateResponseOfReadFSPxx_Event
    6. For Each uc_ctrl As Control In Me.Controls
    7. 'Ordnet einem TextBox-Steuerelement-Ereignishandler zur Laufzeit ein Ereignis zu -> Aufruf von 'mod_Functions_ControlContentOrIndexChanged'
    8. If TypeOf uc_ctrl Is TextBox Then
    9. AddHandler uc_ctrl.TextChanged, _handler
    10. End If
    11. Next
    12. End Sub
    13. Private Sub RemoveHandlers()
    14. RemoveHandler GenericPCAClass.GenericPCAClass_evt_ForwardReadFSPData, AddressOf EvaluateResponseOfReadFSPxx_Event
    15. For Each uc_ctrl As Control In Me.Controls
    16. 'Handler aus AddHandlers weider entfernen
    17. If TypeOf uc_ctrl Is TextBox Then
    18. RemoveHandler uc_ctrl.TextChanged, _handler
    19. End If
    20. Next
    21. End Sub
    22. End Class

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „roepke“ ()

    @roepke Hänge nicht iwelche Dateien an.
    Erstell ein kleines compilierendes Projekt, mit dem man den Effekt untersuchen kann,
    also diese Klasse und alle Hilfsklassen oder ersetze diese durch elementart Contgrols (ProgressBar).
    Zippe das und hänge es ohne obj, bin, vs-Ordner an.
    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!

    Neu

    So, hat etwas gedauert, aber hier ist mal eine auf das nötigste abgespeckte Version meines Projekts.
    Nach dem Starten im ‚frm_ICM_7_5’ eine der ‚SPI CHx‘ TabPages anwählen und über ‚Select connected module on SPIx CHx‘ ein UserControl hinzufügen, bzw. ändern/entfernen.
    Es stehen das SPI IO Extension und SPI ADC Extension zur Verfügung.
    Diese legen in ihrer ‚LoadThisUserControl_Load()‘ Handler an.
    Beispiel ADC SPI Extension: Beim Entfernen des UserControls sollen dessen Handler natürlich auch wieder entfernt werden. Dazu habe ich im UserControl ‚UserControleDisposed()‘ eingebaut. Das funzt aber nicht, da darin ‚RemoveHandlers()‘ zwar noch aufgerufen wird und in ‚RemoveHandlers()‘ dann aber die Controls die mit dem Handler verknüpft sind wohl nicht mehr existent sind.

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

    Neu

    @roepke Schmeiß mal bei einem Datei-Anhang die obj, bin und vs-Verzeichnisse raus (bereinigen).
    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!

    Neu

    @roepke OK.
    Pack mal die RemoveHandlers()-Aufrufe von Private Sub UserControleDisposed() Handles Me.Disposed nach Protected Overrides Sub Dispose(ByVal disposing As Boolean) in der xxx.Designer.vb.
    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!

    Neu

    @RodFromGermany
    Scheint zu funktionieren.
    Ich hatte immer etwas Bammel in der x.designer.vb rumzubasteln.
    Werden diese Einträge nicht überschrieben oder wird wird Protected Overrides Sub Dispose(ByVal disposing As Boolean) nur einmalig angelegt und anschließend nicht mehr angefasst?
    Die in Private Sub InitializeComponent() ändern sich ja auf jeden Fall mit Veränderungen im Form.

    Neu

    roepke schrieb:

    Ich hatte immer etwas Bammel in der x.designer.vb rumzubasteln.
    Jo, finde ich auch gruselig.
    Ich verschiebe gerne die Protected Overrides Sub Dispose(ByVal disposing As Boolean) in meinen UserCode, wo ich sie sehen kann, und weiss, dass der Designer sie da nicht rewritet.
    Aber tatsächlich ist er glaub garnet soo böse.
    Zum beispiel kann man bei InitializeComponents() das idiotische DebuggerstepThrough-Attribut wegmachen, und er machts auch nicht wieder hin, erfreulicherweise.