Event-Handler wird nicht ausgeführt

  • VB.NET

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    Event-Handler wird nicht ausgeführt

    Hallo.

    Ich habe das Problem, dass ein Event-Handler nicht ausgeführt wird, sobald RaiseEvent Eventname ausgeführt wird.
    Das selbe Problem hatte auch jemand in diesem Forum.

    Der Code, reduziert auf das nötige, sieht so aus (Das UserControl befindet sich in einer eigenen Dll):
    Spoiler anzeigen

    Form1, die StartForm der Testanwendung:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Initialize() Handles MyBase.Load
    3. RegisterView1.Initialize()
    4. End Sub
    5. End Class


    StructureWrapperClass, das ist ein Wrapper für Structures, damit man diese als Typenparameter angeben kann.

    VB.NET-Quellcode

    1. 'Da Typenparameter keine Structures sein können, muss ein Wrapper her, der die entsprechende Structure beinhaltet.
    2. 'Die Basisklasse ist nötig, dass beim Typenparameter (Of T >>As StructureWrapperClass<<) angegeben werden kann.
    3. 'Dadurch wird der Typ auf eine dieser Klassen beschränkt.
    4. Public MustInherit Class StructureWrapperClass
    5. End Class
    6. 'Wrapper für eine 8-Bit Zahl
    7. Public Class WrapperByte
    8. Inherits StructureWrapperClass
    9. Public Property Value As Byte
    10. Public Sub New(ByVal NewValue As Byte)
    11. Value = NewValue
    12. End Sub
    13. 'Um bei MessageBox.Show("Transmit1To2: " & NewValue.ToString) etwas sinnvolles herauszubekommen
    14. Public Overrides Function ToString() As String
    15. Return "WrapperByte " & Value.ToString
    16. End Function
    17. End Class


    RegisterView, ein UserControl:

    VB.NET-Quellcode

    1. Public Class RegisterView
    2. Dim _Frames As New Frames
    3. Dim _Arrows As New Arrows(_Frames.EEPROM, _Frames.InstructionBus)
    4. Public Sub Initialize()
    5. _Frames.Initialize()
    6. End Sub
    7. 'Hier drin befinden sich alle Instanzen von Klassen, die von Frame abgeleitet sind
    8. Public Class Frames
    9. 'Der EEPROM wird mit einem Arrow(Of WrapperByte) mit dem InstructionBus verbunden
    10. Public EEPROM As Frame.EEPROM
    11. Public InstructionBus As Frame.BUSWire.InstructionBus
    12. Public Sub New()
    13. 'Alle Instanzen erstellen
    14. EEPROM = New Frame.EEPROM
    15. InstructionBus = New Frame.BUSWire.InstructionBus
    16. End Sub
    17. Public Sub Initialize()
    18. EEPROM.Initialize()
    19. End Sub
    20. End Class
    21. 'Hier befinden sich alle Instanzen von Arrow
    22. Public Class Arrows
    23. Public EEPROM_DataBus As Arrow(Of WrapperByte)
    24. Public Sub New(ByVal EEPROM As Frame.EEPROM, ByVal InstructionBus As Frame.BUSWire.InstructionBus)
    25. 'Alle Instanzen erstellen
    26. 'Man beachte, dass die jeweiligen DockPoints angebgeben werden.
    27. EEPROM_DataBus = New Arrow(Of WrapperByte)(EEPROM.Dock_ToInstructionBus, InstructionBus.Dock_ToEEPROM)
    28. End Sub
    29. End Class
    30. 'Die Basisklasse, von der alle Baugruppen abgeleitet sind
    31. Public MustInherit Class Frame
    32. 'Nimmt eine Adresse und sendet das Byte an der Adresse weiter
    33. Public Class EEPROM
    34. Inherits Frame
    35. Public Dock_ToInstructionBus As ArrowDockPoint(Of WrapperByte)
    36. Public Sub New()
    37. Dock_ToInstructionBus = New ArrowDockPoint(Of WrapperByte)
    38. End Sub
    39. 'Löst das erstmalige Senden des Bytes an Adresse 0 aus
    40. 'Zum Testen wird immer 8 gesendet
    41. Public Sub Initialize()
    42. PushValue()
    43. End Sub
    44. Public Sub PushValue()
    45. Dock_ToInstructionBus.PushValue(New WrapperByte(8))
    46. End Sub
    47. End Class
    48. 'Verbindet mehrere Frames miteinander
    49. Public MustInherit Class BUSWire
    50. Inherits Frame
    51. 'Ein 8-Bit Bus (Darum wird WrapperByte verwendet)
    52. Public Class InstructionBus
    53. Inherits BUSWire
    54. Public WithEvents Dock_ToEEPROM As ArrowDockPoint(Of WrapperByte)
    55. Public Sub New()
    56. Dock_ToEEPROM = New ArrowDockPoint(Of WrapperByte)
    57. End Sub
    58. End Class
    59. End Class
    60. End Class
    61. 'Ein "Andockpunkt" für Arrows
    62. 'Löst als Sender das Event TransmitValue aus, welches vom Arrow behandelt wird, oder
    63. '(hier nicht gezeigt) wird vom Arrow als Empfänger verwendet, um das Gegenstück bei einer Übertragung darzustellen
    64. Public Class ArrowDockPoint(Of T As StructureWrapperClass)
    65. Public Event TransmitValue(ByVal NewValue As T)
    66. Public Sub PushValue(ByVal NewValue As T)
    67. RaiseEvent TransmitValue(NewValue) 'Diese Zeile wird ausgeführt, aber es wird nicht zum EventHandler gesrpungen
    68. End Sub
    69. End Class
    70. 'Verbindet zwei ArrowDockPoints und übergibt Werte vom ersten zum zweiten oder umgekehrt
    71. Public Class Arrow(Of T As StructureWrapperClass)
    72. Dim WithEvents DockPoint1 As ArrowDockPoint(Of T)
    73. Dim WithEvents DockPoint2 As ArrowDockPoint(Of T)
    74. Public Sub New(ByVal NewDockPoint1 As ArrowDockPoint(Of T), ByVal NewDockPoint2 As ArrowDockPoint(Of T))
    75. DockPoint1 = NewDockPoint1
    76. DockPoint2 = NewDockPoint2
    77. End Sub
    78. 'Ein Wert wird vom ersten ArrowDockPoint zum zweiten übergeben
    79. 'Dies ist der EventHandler für das TransmitValue-Event; Und er wird nicht ausgeführt, wenn das Event ausgelöst wird.
    80. Private Sub Transmit1To2(ByVal NewValue As T) Handles DockPoint1.TransmitValue
    81. If Debugger.IsAttached Then Debugger.Break()
    82. MessageBox.Show("Transmit1To2: " & NewValue.ToString)
    83. End Sub
    84. End Class
    85. End Class



    Ich habe den Code mal in einer Testanwendung probiert, aber da läuft er problemlos.

    Wenn man die Anwendung startet, kommt es zu einer Reihe von Aufrufen, bis Debugger.Break() bei Zeile 96 aufgerufen wird.
    Die Methode Transmit1To2 bei Zeile 95 behandelt das TransmitValue-Event von DockPoint1, welches durch RaiseEvent TransmitValue(NewValue) bei Zeile 80 ausgelöst wird.

    Das Problem: Im richtigen Programm wird diese Methode nicht ausgeführt.
    Das Event wird zwar ausgelöst (getestet durch Hinzufügen eines weiteren Handlers), aber wenn man einen Haltepunkt auf Zeile 80 setzt und einen Einzelschritt macht, dann wird nirgends hin gesprungen, sondern einfach mit der nächsten Zeile weitergemacht.

    Ich habe auch schon probiert im Konstruktor von Arrow per AddHandler die EventHandler mit den Events zu verknüpfen, aber das bleibt genauso erfolglos.

    Zum Test habe ich den Code aus der Assembly mal in das Projekt kopiert, in dem ich sie verwende und vorher den Verweis gelöscht. Natürlich stimmt dann das Namespace nicht, deshalb habe ich das noch ausgebessert.
    Und erstaunlich: So funktioniert es!

    Und ich habe auch schon versucht den vereinfachten Code in eine Dll auszulagern. Da funktioniert es immer noch.

    Mir gehen echt die Ideen aus.

    Moment!
    Jetzt habe ich das Dll-Projekt mal auf den Desktop verschoben, ein neues Projekt mit dem selben Namen erstellt, den ganzen Code übernommen (1:1 C&P) und dieses an die Stelle des alten Projektes gesetzt. Dll neu kompiliert, Projekt geöffnet und schon hat's einwandfrei funktioniert.

    Wie zum Teufel kann das möglich sein?
    Nur weil's mich interessiert: Mal sehen, ob es jetzt funktioniert, wenn ich den Verweis mal auf das alte Projekt setze (ohne das alte Projekt zurückzukopieren). Jetzt geht's auch ?(
    Will Microsoft mich ärgern? :cursing:

    Ich versteh's einfach nicht. Also wer mir das erklären kann kriegt 'nen Keks.


    Edit: Jetzt funktioniert es schon wieder nicht.
    Und jetzt funktioniert das Anlegen eines neuen Projektes auch nicht mehr.
    Es ist echt zum Durchdrehen!
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

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

    Hi,

    ich habe obigen Code in ein Testprojekt kopiert und analysiert. Das zweite Event wird nicht ausgelöst. Das ist aber ganz logisch, denn du rufst es nicht auf.

    Die Initialisierung ist komplett in Ordnung - es werden zwei ArrowDockPoints erstellt - der eine wird an das EEPROM gebunden, der andere an den InstructionBus. Beide ArrowDockPoints werden auch korrekt mit dem jeweiligen Handler verbunden. So gesehen ist der oberste Aufruf "...As New RegisterView" in Ordnung. Dann kommt der Aufruf von Initialize(). Das geht weiter zu _Frames.Initialize(). An dieser Stelle wird EEPROM.Initialize() aufgerufen, wodurch in der Folge das erste Event gefeuert wird (über EEPROM.Initialize(), EEPROM.PushValue(), Dock_ToInstructionBus.PushValue(...), RaiseEvent). Dann ist die Sub beendet - wo wird also das zweite Event aufgerufen? Nirgendwo. Also wird es auch nicht ausgelöst.

    Ich nehme an, dass du die Klassen, die von Frame erben, polymorph gestallten wolltest - du hast aber einen Teil davon vergessen. Lösung: Siehe Expander. Die geänderten Stellen sind kommentiert.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    3. Dim rv As New RegisterView
    4. rv.Initialize()
    5. End Sub
    6. End Class
    7. Public Class RegisterView
    8. Dim _Frames As Frames
    9. Dim _Arrows As Arrows
    10. Public Sub New()
    11. _Frames = New Frames
    12. _Arrows = New Arrows(_Frames.EEPROM, _Frames.InstructionBus)
    13. End Sub
    14. Public Sub Initialize()
    15. _Frames.Initialize()
    16. End Sub
    17. Public Class Frames
    18. 'Public EEPROM As Frame.EEPROM
    19. 'Public InstructionBus As Frame.BUSWire.InstructionBus
    20. 'Deklaration muss nicht (mehr) spezifisch sein
    21. Public EEPROM As Frame
    22. Public InstructionBus As Frame
    23. Public Sub New()
    24. EEPROM = New Frame.EEPROM
    25. InstructionBus = New Frame.BUSWire.InstructionBus
    26. End Sub
    27. Public Sub Initialize()
    28. EEPROM.Initialize()
    29. InstructionBus.Initialize() 'Das löst das zweite Event aus!
    30. End Sub
    31. End Class
    32. Public Class Arrows
    33. Public EEPROM_DataBus As Arrow(Of Byte)
    34. Public Sub New(ByVal EEPROM As Frame.EEPROM, ByVal InstructionBus As Frame.BUSWire.InstructionBus)
    35. EEPROM_DataBus = New Arrow(Of Byte)(EEPROM.Dock_ToInstructionBus, InstructionBus.Dock_ToEEPROM)
    36. End Sub
    37. End Class
    38. Public MustInherit Class Frame
    39. 'Polymorphie verwenden
    40. MustOverride Sub Initialize()
    41. Public Class EEPROM
    42. Inherits Frame
    43. Public Dock_ToInstructionBus As ArrowDockPoint(Of Byte)
    44. Public Sub New()
    45. Dock_ToInstructionBus = New ArrowDockPoint(Of Byte)
    46. End Sub
    47. 'als Overrides deklariert
    48. Public Overrides Sub Initialize()
    49. PushValue()
    50. End Sub
    51. Public Sub PushValue()
    52. Dock_ToInstructionBus.PushValue(5)
    53. End Sub
    54. End Class
    55. Public MustInherit Class BUSWire
    56. Inherits Frame
    57. Public Class InstructionBus
    58. Inherits BUSWire
    59. Public WithEvents Dock_ToEEPROM As ArrowDockPoint(Of Byte)
    60. Public Sub New()
    61. Dock_ToEEPROM = New ArrowDockPoint(Of Byte)
    62. End Sub
    63. 'Hinzugefügt
    64. Overrides Sub Initialize()
    65. Dock_ToEEPROM.PushValue(6)
    66. End Sub
    67. End Class
    68. End Class
    69. End Class
    70. Public Class ArrowDockPoint(Of T)
    71. Shared i As Int32 = 0
    72. Public Event TransmitValue(ByVal NewValue As T)
    73. Public objid As Int32
    74. Public Sub New()
    75. i += 1
    76. objid = i
    77. End Sub
    78. Public Sub PushValue(ByVal NewValue As T)
    79. RaiseEvent TransmitValue(NewValue)
    80. End Sub
    81. End Class
    82. Public Class Arrow(Of T)
    83. Dim WithEvents DockPoint1 As ArrowDockPoint(Of T)
    84. Dim WithEvents DockPoint2 As ArrowDockPoint(Of T)
    85. Public Sub New(ByVal NewDockPoint1 As ArrowDockPoint(Of T), ByVal NewDockPoint2 As ArrowDockPoint(Of T))
    86. DockPoint1 = NewDockPoint1
    87. DockPoint2 = NewDockPoint2
    88. End Sub
    89. Private Sub Transmit1To2(ByVal NewValue As T) Handles DockPoint1.TransmitValue
    90. 'If Debugger.IsAttached Then Debugger.Break()
    91. MessageBox.Show("Transmit1To2: " & NewValue.ToString)
    92. End Sub
    93. Private Sub Transmit2To1(ByVal NewValue As T) Handles DockPoint2.TransmitValue
    94. 'If Debugger.IsAttached Then Debugger.Break()
    95. MessageBox.Show("Transmit2To1: " & NewValue.ToString)
    96. End Sub
    97. End Class
    98. End Class

    In deinem Code gibt es noch einen Fehler, den mein Compiler nicht akzeptiert hat. Klar - er kannte WrapperByte nicht, also habe ich alle WrapperByte-Angaben in Byte geändert. Aber an dieser Stelle (in der Klasse EEPROM) moniert er das Array:

    VB.NET-Quellcode

    1. Dock_ToInstructionBus.PushValue(New WrapperByte(8))
    , denn du hast Dock_ToInstructionBus als

    VB.NET-Quellcode

    1. Public Dock_ToInstructionBus As ArrowDockPoint(Of WrapperByte)
    und nicht als

    VB.NET-Quellcode

    1. Public Dock_ToInstructionBus As ArrowDockPoint(Of WrapperByte())
    deklariert.

    Achtung: Ich musste auch die Angabe "As StructureWrapperClass" entfernen, damit ich den Code debuggen konnte. Neben der Änderung von WrapperByte in Byte musst du die ebenfalls rückgängig machen.
    Gruß
    hal2000
    Vielleicht ist es sinnvoll, mit New RegisterView1 eine gültige Instanz von RegisterView1 zu erstellen, auf die sich Deine Events beziehen.
    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!
    @RodFromGermany:
    RegisterView1 ist die Instanz von RegisterView, die vom Designer erstellt wurde, als ich das Control auf Form1 gezogen habe.

    @hal2000:
    Hoppala. Ich habe noch vergessen die StructureWrapperClass hinzuzufügen.
    Es handelt sich hierbei (Wie der Name schon sagt) um einen Wrapper für eine Structure, da Typenparameter keine Structures sein können.
    Hier die StructureWrapperClass:

    VB.NET-Quellcode

    1. 'Die Basisklasse ist nötig, dass beim Typenparameter (Of T >>As StructureWrapperClass<<) angegeben werden kann.
    2. 'Dadurch wird der Typ auf eine dieser Klassen beschränkt.
    3. Public MustInherit Class StructureWrapperClass
    4. End Class
    5. 'Wrapper für eine 8-Bit Zahl
    6. Public Class WrapperByte
    7. Inherits StructureWrapperClass
    8. Public Property Value As Byte
    9. Public Sub New(ByVal NewValue As Byte)
    10. Value = NewValue
    11. End Sub
    12. End Class
    13. 'Wrapper für eine 16-Bit Zahl
    14. Public Class WrapperUInt16
    15. Inherits StructureWrapperClass
    16. Public Property Value As UInt16
    17. Public Sub New(ByVal NewValue As UInt16)
    18. Value = NewValue
    19. End Sub
    20. End Class


    Das zweite Event wird wirklich nicht ausgelöst (Das wäre bei InstructionBus.Dock_ToEEPROM.PushValue()). Das ist auch Absicht, denn das funktioniert im Programm ja auch.
    Das Problem liegt beim Behandeln des TransmitValue-Eventes der EEPROM-Klasse (Sollte von Transmit1To2() behandelt werden).
    wodurch in der Folge das erste Event gefeuert wird (über [...], RaiseEvent). Dann ist die Sub beendet

    Das hat es genau getroffen! RaiseEvent wird aufgerufen, dann ist die Sub beendet. Aber es wird nicht zu Transmit1To2() gesprungen. Beim Testprogramm schon, aber in dem Programm, das ich vor mir habe nicht.



    Das mit dem Initialize hast Du jetzt anders verstanden, als es gemeint war.
    Beim Starten der Anwendung (MyBase.Load) muss der EEPROM (von dem gibt's nur eine Instanz) einmal ein Byte (bzw. ein WrapperByte) auf den InstructionBus "Pushen". Dieses Byte wird dann von einem anderen Register aufgenommen und gespeichert.
    Das was jetzt folgt ist etwas weiter ausgeholt, also genau lesen:
    Wenn man ein Control im Designer verwenden will, muss es eine zugreifbare Sub New ohne Parameter haben.
    Der EEPROM muss aber irgendwo her die Informationen bekommen, was er bei welcher Adresse auf den InstructionBus schreiben muss.
    Diese Quelle würde ich schon im Konstruktor mitgeben, was aber wie gesagt wegen dem Designer nicht möglich ist.
    Darum wird in der MyBase.Load Sub Initialize aufgerufen. Diese erwartet dieses Interface:

    VB.NET-Quellcode

    1. Public Interface IInstructionSource
    2. Function GetInstruction(ByVal Address As UInt16) As Byte
    3. End Interface

    , bei dem der EEPROM GetInstruction() aufruft um das zu schreibende Byte zu bekommen.
    In der Initialize Sub wird _Frames.Initialize() aufgerufen und die Referenz auf die Quelle wird weitergegeben.
    Dort wird einmal das Übertragen des Wertes vorbereitet, sodass der Wert vom anderen Register überhaupt gespeichert wird, und dann wird EEPROM.Initialize() aufgerufen (wobei EEPROM hier eine Instanz von Frame.EEPROM ist; nur um nicht Klassen mit Instanzen zu verwechseln). Auch hier wird die Referenz auf die Quelle weitergereicht.
    Jetzt wird diese Referenz in eine Variable abgelegt, dann wird PushValue() aufgerufen.
    In der PushValue Sub wird das Byte von der Quelle geholt und Dock_ToInstructionBus.PushValue(New WrapperByte(DasByteVonDerQuelle)) aufgerufen.
    Und dann wären wir wieder beim Problem. In der ArrowDockPoint.PushValue Sub wird zwar RaiseEvent TransmitValue(NewValue) aufgerufen, aber der entsprechende EventHandler wird nicht ausgeführt. Wenn alles funktionieren würde, dann würde zu Transmit1To2() gesrpungen werden und es würde eine weitere Methode aufgerufen werden, die schlussendlich den Wert vom einen zum anderen ArrowDockPoint übertragen würde.

    *Luft hol* ... sooooo.

    Wie Du das mit der Polymorphie gemeit hast habe ich nicht ganz verstanden. Aber ich bin mir sicher, dass ich nichts vergessen habe.
    Es geht mir lediglich darum die ArrowDockPoints und Arrows polymorph zu gestalten, da ich mir dadurch Arbeit spare.
    Die Klassen, die von der Klasse Frame erben definieren, welcher Typ verwendet werden soll. Z.B. der EEPROM verwendet als einerseits ein WrapperUInt16 für die Adresse und andererseits ein WrapperByte für das Byte, dass er ausgeben soll.
    Das, was mit den Codeschnippseln am Ende Deines Beitrages zusammenhängt erübrigt sich, wenn man die StructureWrapperClass ins Programm einfügt.
    Kleine Erklärung:
    New WrapperByte(8) ist kein Array, sondern eine Instanz von WrapperByte (WrapperByte erbt von StructureWrapperClass), mit dem ge"wrappten" Wert 8.

    Ich werde am Code im StartPost noch ein paar Änderungen vornehmen, wodurch man es hoffentlich etwas leichter versteht.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Ah - genauer lesen :) . Ok - da es um die 1To2-Methode geht:

    Teste mal eine etwas aufgemotzte ArrowDockPoint-Klasse:

    VB.NET-Quellcode

    1. Public Class ArrowDockPoint(Of T As StructureWrapperClass)
    2. Public Sub New()
    3. Debug.Print("creating new ArrowDockPoint instance")
    4. End Sub
    5. Dim TransmitValueEvent As Action(Of T)
    6. Public Custom Event TransmitValue As Action(Of T)
    7. AddHandler(value As Action(Of T))
    8. If TransmitValueEvent Is Nothing Then
    9. TransmitValueEvent = value
    10. Else
    11. [Delegate].Combine(TransmitValueEvent, value)
    12. End If
    13. Debug.Print("handler added. target will be: " & value.Method.Name)
    14. End AddHandler
    15. RemoveHandler(value As Action(Of T))
    16. [Delegate].Remove(TransmitValueEvent, value)
    17. Debug.Print("handler removed. target was: " & value.Method.Name)
    18. End RemoveHandler
    19. RaiseEvent(obj As T)
    20. If TransmitValueEvent IsNot Nothing Then
    21. Debug.Print("invoking all TransmitValueEvent handlers:")
    22. For Each d In TransmitValueEvent.GetInvocationList()
    23. Debug.Print("target: " & d.Method.Name)
    24. Next
    25. TransmitValueEvent.Invoke(obj)
    26. Else
    27. Debug.Print("cannot invoke: No handler available.")
    28. End If
    29. End RaiseEvent
    30. End Event
    31. Public Sub PushValue(ByVal NewValue As T)
    32. RaiseEvent TransmitValue(NewValue) 'Diese Zeile wird ausgeführt, aber es wird nicht zum EventHandler gesrpungen
    33. End Sub
    34. End Class

    Ich könnte mir vorstellen, dass irgendwo implizit eine Kopie einer ArrowDockPoint-Instanz erstellt wird, da du scheinbar mit vielen Strukturen arbeitest. Wenn die kopiert werden, weden die Daten (Werttypen) mitkopiert, aber nicht die enthaltenen Referenztypen (flache Kopie).

    Dir geht irgendwo stillschweigend die Instanz des Delegaten verloren, die den Handler darstellt. Wenn du das Leben der Delegateninstanz ab AddHandler nachverfolgst, müsstest du den Fehler finden. Wenn du wieder die WithEvents-Variante benutzt, kannst du auch nachverfolgen, wann automatisch RemoveHandler aufgerufen wird (das sagt dir dein Custom Event). Setze dort einen Haltepunkt rein, dann müsste der Auslöser im Aufrufstack stehen.

    Vielleicht bricht dir auch die seltsame Schachtelung der Klassen das Genick, denn das erschwert das Verständnis ungemein. Auch über 2500 Zeilen Code in einer Datei sind eigentlich ein No-Go.

    Mein Vorschlag mit der Polymorphie sollte eigentlich nur sagen, dass die Deklarationen von EEPROM und InstructionBus (den Variablen in Frames) besser die Basisklasse deklarieren sollten, um ein wenig Komplexität dem Compiler zu überlassen.
    Gruß
    hal2000
    (Hat sich erledigt. Siehe weiter unten. Falls es Dich trotzdem interessiert kannst Du es trotzdem durchlesen.)


    Hallo und erst mal danke für Deine Mühe.

    Ich habe es jetzt mit dem Custom Event probiert.
    Ich habe einen Haltepunkt bei Add- und RemoveHandler im Custom Event gesetzt und die Anwendung gestartet.
    Der Debugger hält beim Haltepunkt im AddHandler-Teil (wie zu erwarten). Dann bin ich im Einzelschrittdebugging mal von dort aus weiter gegangen. Es gibt keine Probleme. RemoveHandler wird nie aufgerufen. Irgendwann bin ich dann zum bekannten Initialize gekommen. Ich bin bis zu EEPROM.Initialize() weiter gegangen, bis PushValue und bis RaiseEvent TransmitValue.
    Das interessante: Der RaiseEvent-Teil im Custom Event wird ausgeführt, aber TransmitValueEvent ist Nothing.

    RemoveHandler wurde aber nie ausgeführt. Und ich habe im Einzelschrittdebugging genau gesehen, dass für den Arrow, der den EEPROM mit dem InstructionBus verbindet, als DockPoint1 der Dock_ToInstructionBus vom EEPROM verwendet wird. Und das ist auch genau der ArrowDockPoint, der beim Screenshot zu sehen ist.

    dass irgendwo implizit eine Kopie einer ArrowDockPoint-Instanz erstellt wird

    Gut möglich. Vielleicht finde ich im mit IL-Spy irgendwas in der Richtung.



    OMG ich hab's gefunden!
    Oh mann, da muss aber auch erst jemand drauf kommen.
    Ich habe versucht im Einzelschrittdebugging vom Instanzieren der Form, die das Control beinhaltet, weg so lange weiter zu klicken, bis TransmitValueEvent auf Nothing gesetzt wird.
    Ich bin auch den Code in InitializeComponent() durchgegangen, indem ich das DebuggerStepThrough-Attribut rausgenommen habe.
    Ich gehe schön die ganzen Konstruktoren der Frame-Klassen durch, alles perfekt. Dann komme ich plötzlich zu dieser Zeile in der InitializeComponent Methode der Form:

    VB.NET-Quellcode

    1. Me.RegisterView_Registers = New RegisterView.RegisterView()

    Das hat mich etwas stutzig gemacht. Denn eine Instanz vom UserControl zu erstellen führt dazu, dass eine Instanz der Frames klasse erstellt wird und dann alle Instanzen der Frame-Klassen erstellt werden. Aber genau das ist doch gerade eben schon passiert.
    Dann habe ich mir den Code nochmal ganz genau angeschaut, und ich habe das gefunden:

    VB.NET-Quellcode

    1. Private Sub InitializeComponent()
    2. Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(Form_Simulator))
    3. Dim Frames2 As RegisterView.RegisterView.Frames = New RegisterView.RegisterView.Frames() 'WTF?
    4. 'Ein paar Controls
    5. Me.RegisterView_Registers = New RegisterView.RegisterView()
    6. 'Noch mehr Controls
    7. 'Hier werden die Eigenschaften der Controls festgelegt.
    8. 'Einige Controls
    9. '
    10. 'RegisterView_Registers
    11. '
    12. Me.RegisterView_Registers._Frames = Frames2 'Und dann diese kleine hübsche Zeile hier!
    13. Me.RegisterView_Registers.BackColor = System.Drawing.Color.White
    14. Me.RegisterView_Registers.Location = New System.Drawing.Point(0, 0)
    15. Me.RegisterView_Registers.Name = "RegisterView_Registers"
    16. Me.RegisterView_Registers.Size = New System.Drawing.Size(1080, 662)
    17. Me.RegisterView_Registers.TabIndex = 0

    Es wird also eine Instanz von Frames erstellt, dann wird die Instanz (vom Konstruktor des UserControls) nochmal erstellt, und dann wird diese Instanz mit der vorhin erstellten überschrieben.
    Ich habe Zeile 3 und 13 rausgenommen und.... siehe da: Es funktioniert perfekt!
    Dieser verflixte Designer hat mir dazwischengefunkt.
    Aber mich wundert es warum er überhaupt den Blödsinn eingefügt hat. Denn normalerweise macht er das nur mit Properties. _Frames und _Arrows sind aber nur als Public deklariert.

    Wie dem auch sei.
    Danke Dir, hal2000, für Deine Bemühungen! Jetzt funktioniert es richtig.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Niko Ortner schrieb:

    Aber mich wundert es warum er überhaupt den Blödsinn eingefügt hat.

    Er ist wahrscheinlich über die Schachtelung der Klassen oder über die vielen Generics gestolpert. Vielleicht konnte irgendein Teil davon nicht direkt erstellt werden, sodass der Designer das in zwei Schritte aufgeteilt hat. Ist aber nur eine Vermutung.
    Schön jedenfalls, dass es nun funktioniert.

    Edit:
    Denn normalerweise macht er das nur mit Properties
    Moment: Da war was. Du benutzt VB 2010 - dort gibt es ein neues Feature, das sich "automatisch implementierte Eigenschaften" nennt. Es reicht aus, folgendes zu schreiben:

    VB.NET-Quellcode

    1. [Modifier] Property MyPropName As [Typ]
    Der Compiler macht daraus folgendes:

    VB.NET-Quellcode

    1. Private _MyPropName As [Typ]
    2. [Modifier] Property MyPropName As [Typ]
    3. Get
    4. Return _MyPropName
    5. End Get
    6. Set(ByVal value as [Typ])
    7. _MyPropName = value
    8. End Set
    9. End Property


    Du hast deine Public-Variable _Frames genannt, und der Designer hat das wohl als öffentliche Property-Backupvariable interpretiert.
    Gruß
    hal2000

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

    @hal2000: Das wäre möglich.
    Aber ich habe der Variable mal das <System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)> - Attribut verpasst. Seither hat der Designer das nicht mehr gemacht. Ich weiß nicht genau, ob das das Problem wirklich gelöst hat, oder ob der Designer das nur zufällig noch nicht erneut gemacht hat. Aber wenn es wieder passiert weiß ich wo ich suchen muss ^^.
    Ach ja: Die über 2500 Zeilen kommen wegen der vielen Klassen, die von Frame erben und der XML-Dokumentation zustande.
    Aber die Arrow und ArrowDockPoint Klassen kann ich in eine eigene Datei verschieben.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils