Event aus Unterklasse durch Hauptklasse tunneln

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

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Event aus Unterklasse durch Hauptklasse tunneln

    Hey Ihr lieben!

    Ich hab da mal wieder ein Event-Problemchen ;)

    Folgender Aufbau liegt vor:

    VB.NET-Quellcode

    1. Namespace Webmana
    2. Partial Public Class BitcoinAPI
    3. Public WithEvents OrderbookL2 as new clOrderbookL2()
    4. Public Class clOrderbookL2
    5. ' -- Events
    6. Public Event Update(sender as Webmana.BitcoinAPI.clOrderbookL2)
    7. ' -- Privates
    8. Private Sub incomingUpdate()
    9. RaiseEvent Update(Me)
    10. End sub
    11. End Class
    12. End Class
    13. End Namespace


    Wie bekomme ich das Ereignis (Event) auf meine Form? Muss ich das durch die Hauptklasse tunneln?

    VB.NET-Quellcode

    1. Public Class Form1
    2. Public WithEvents API As New Webmana.BitcoinAPI()
    3. Private Sub API_OrderbookL2Updated(sender as object) Handles API.OrderbookL2.Updated '<-- Warum geht das so nicht?
    4. ' Tuh was..
    5. End Sub
    6. End Class


    Vielleicht weiß ja jemand eine schicke Lösung, also mal eine die besser aussieht, als das Event in der Hauptklasse durch einen Handler und ein weiteres Event durch zu schleifen.

    Danke schonmal! - Lg Hassowuff
    __________________________
    01:
    CLS : SCREEN 12
    02: LINE (0, 20)-(640, 22), 15, BF
    03: ECHO "MFG HASSOWUFF"
    [F5]
    Meh, geschachtelte Klassen …
    Du könntest es zur Laufzeit binden:

    VB.NET-Quellcode

    1. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. AddHandler API.OrderbookL2.Update, AddressOf API_OrderbookL2_Update
    3. End Sub
    4. Private Sub API_OrderbookL2_Update(sender As Object)
    5. 'whatever
    6. End Sub
    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.
    @hassowuff Der Empfänger des Events muss dann ggf. die EventArgs an einen höheren Empfänger durchreichen, so lange, bis der finale Empfänger erreicht ist.
    Und:
    Events in .NEZ haben eine Signatur, da ist immer der Sender als Object und Event-spezifische Event-Argumente, im einfachsten Fall EventArgs, ansonsten eine von EventArgs abgeleitete eigene MyEventArgs-Klasse.
    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!
    Im Prinzip habe ich das Event durch die Hauptklasse getunnelt, weil ich auf einen modularer Aufbau setze und möchte, dass man jedes mögliche Event in der Code-Ansicht / Drop-Down-Liste oben aufgelistet bekommt.

    Hauptklasse:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Globalization
    2. Imports System.IO
    3. Imports System.Runtime.Serialization.Formatters.Binary
    4. Imports Newtonsoft.Json.Linq
    5. Namespace Webmana
    6. Partial Public Class BitcoinAPI
    7. ' --- Propertys ------------------------------------------------------
    8. Private _isConnected As Boolean = False
    9. Public ReadOnly Property isConnected() As Boolean
    10. Get
    11. Return _isConnected
    12. End Get
    13. End Property
    14. Private _apiKey As String = "123.."
    15. Public Property apiKey() As String
    16. Get
    17. Return _apiKey
    18. End Get
    19. Set(ByVal value As String)
    20. _apiKey = value
    21. End Set
    22. End Property
    23. Private _apiSecure As String = "abc.."
    24. Public Property apiSecureToken() As String
    25. Get
    26. Return _apiSecure
    27. End Get
    28. Set(ByVal value As String)
    29. _apiSecure = value
    30. End Set
    31. End Property
    32. Private _isAuthentified As Boolean = False
    33. Public ReadOnly Property isAuthentified() As Boolean
    34. Get
    35. Return _isAuthentified
    36. End Get
    37. End Property
    38. Private _isReadOnly As Boolean = True
    39. Public ReadOnly Property isReadOnly() As Boolean
    40. Get
    41. Return _isReadOnly
    42. End Get
    43. End Property
    44. Private _autoAuthenticate As Boolean = True
    45. Public Property autoAuthenticate() As Boolean
    46. Get
    47. Return _autoAuthenticate
    48. End Get
    49. Set(ByVal value As Boolean)
    50. _autoAuthenticate = value
    51. End Set
    52. End Property
    53. ' --- Public's -------------------------------------------------------
    54. ' --- Private's ------------------------------------------------------
    55. Private apiUrl As String = "wss://ws.prod.blockchain.info/mercury-gateway/v1/ws"
    56. Private apiOrigin As String = "https://exchange.blockchain.com"
    57. Private apiFriendlyName As String = "Blockchain Exchange API"
    58. Private websocket As New WebSocket4Net.WebSocket(Me.apiUrl,,,, Me.apiFriendlyName, Me.apiOrigin, WebSocket4Net.WebSocketVersion.Rfc6455,, Security.Authentication.SslProtocols.Tls12)
    59. ' --- Events ---------------------------------------------------------
    60. Public Event Connected()
    61. Public Event Authenticated()
    62. Public Event Disconnected()
    63. Public Event InternalError(e As EventArgs)
    64. ' --- Subs -----------------------------------------------------------
    65. Public Sub New()
    66. CultureInfo.CurrentCulture = New CultureInfo("en-US", False)
    67. 'websocket = New WebSocket4Net.WebSocket(Me.apiUrl,,,, Me.apiFriendlyName, Me.apiOrigin, WebSocket4Net.WebSocketVersion.Rfc6455,, Security.Authentication.SslProtocols.Tls12)
    68. AddHandler websocket.Opened, AddressOf socketOpened
    69. AddHandler websocket.Error, AddressOf socketError
    70. AddHandler websocket.Closed, AddressOf socketClosed
    71. AddHandler websocket.MessageReceived, AddressOf socketMessage
    72. AddHandler websocket.DataReceived, AddressOf socketDataReceived
    73. End Sub
    74. Public Sub New(ApiKey As String, ApiSecureToken As String, Optional autoConnect As Boolean = True, Optional autoAuthenticate As Boolean = True)
    75. CultureInfo.CurrentCulture = New CultureInfo("en-US", False)
    76. 'websocket = New WebSocket4Net.WebSocket(Me.apiUrl,,,, Me.apiFriendlyName, Me.apiOrigin, WebSocket4Net.WebSocketVersion.Rfc6455,, Security.Authentication.SslProtocols.Tls12)
    77. AddHandler websocket.Opened, AddressOf socketOpened
    78. AddHandler websocket.Error, AddressOf socketError
    79. AddHandler websocket.Closed, AddressOf socketClosed
    80. AddHandler websocket.MessageReceived, AddressOf socketMessage
    81. AddHandler websocket.DataReceived, AddressOf socketDataReceived
    82. Me._apiKey = ApiKey
    83. Me._apiSecure = ApiSecureToken
    84. Me._autoAuthenticate = autoAuthenticate
    85. If autoConnect = True Then
    86. Me.connect()
    87. End If
    88. End Sub
    89. ' --- Socket-Handler -------------------------------------------------
    90. Public Sub connect()
    91. If Me._isConnected = False Then
    92. websocket.Open()
    93. Else
    94. MsgBox("Sie sind bereits verbunden!")
    95. End If
    96. End Sub
    97. Public Sub disconnect()
    98. websocket.Close()
    99. websocket.Dispose()
    100. End Sub
    101. Private Sub socketOpened(s As Object, e As EventArgs)
    102. Me._isConnected = True
    103. RaiseEvent Connected()
    104. If Me._autoAuthenticate = True Then authenticate()
    105. End Sub
    106. Private Sub socketClosed(s As Object, e As EventArgs)
    107. Me._isConnected = False
    108. RaiseEvent Disconnected()
    109. End Sub
    110. Private Sub socketError(s As Object, e As SuperSocket.ClientEngine.ErrorEventArgs)
    111. RaiseEvent InternalError(e)
    112. End Sub
    113. Private Sub socketMessage(s As Object, e As WebSocket4Net.MessageReceivedEventArgs)
    114. If e.Message.Length > 0 And e.Message.StartsWith("{") Then
    115. socketIncome(JObject.Parse(e.Message))
    116. Else
    117. MsgBox("Unbekannte Nachricht emfangen!" & vbNewLine & vbNewLine & e.Message.ToString())
    118. End If
    119. End Sub
    120. Private Sub socketDataReceived(ss As Object, e As WebSocket4Net.DataReceivedEventArgs)
    121. If e.Data.ToString().Length > 0 And e.Data.ToString().StartsWith("{") Then
    122. socketIncome(JObject.Parse(e.Data.ToString()))
    123. Else
    124. MsgBox("Unbekannte Daten emfangen!" & vbNewLine & vbNewLine & e.Data.ToString())
    125. End If
    126. End Sub
    127. Private Sub socketIncome(jResult As JObject)
    128. If jResult.ContainsKey("channel") Then
    129. Select Case jResult("channel")
    130. Case "auth"
    131. If jResult.ContainsKey("event") Then
    132. Select Case jResult("event")
    133. Case "subscribed"
    134. Me._isAuthentified = True
    135. RaiseEvent Authenticated()
    136. If jResult.ContainsKey("readOnly") Then
    137. Me._isReadOnly = jResult("readOnly")
    138. Else
    139. Me._isReadOnly = True
    140. End If
    141. Case Else
    142. MsgBox("Unbekanntes Event!" & vbNewLine &
    143. " - Channel: " & jResult("channel").ToString & vbNewLine &
    144. " - Event: " & jResult("event").ToString)
    145. End Select
    146. End If
    147. Case "ticker"
    148. Case "heartbeat"
    149. Case "balances"
    150. Case "l2"
    151. Case "l3"
    152. MsgBox("Not Implemented: " & jResult("channel").ToString)
    153. Case Else
    154. MsgBox("Unbekannter Kanal: " & jResult("channel").ToString)
    155. End Select
    156. Else
    157. MsgBox("Unbekannte Rückgabe:" & vbNewLine & vbNewLine & jResult.ToString)
    158. End If
    159. End Sub
    160. ' --- API-Functions ---------------------------------------------------
    161. Public Sub authenticate()
    162. If Me._isAuthentified = False Then
    163. If Me._apiKey <> "" And Me._apiSecure <> "" Then
    164. Dim req As JObject = New JObject(
    165. New JProperty("channel", "auth"),
    166. New JProperty("action", "subscribe"),
    167. New JProperty("token", Me._apiSecure)
    168. )
    169. If Me._isConnected = True Then
    170. websocket.Send(req.ToString)
    171. Else
    172. MsgBox("Authentifizierung: Es besteht keine Server-Verbindung!")
    173. End If
    174. Else
    175. MsgBox("Authentifizierung: API-Key oder API-Secure-Token fehlt!")
    176. End If
    177. Else
    178. MsgBox("Sie sind bereits Authentifiziert!")
    179. End If
    180. End Sub
    181. Shared Function DeepCopyList(Of T)(origin As T) As T
    182. Using InMemory As New MemoryStream
    183. Dim binaryFormatter As New BinaryFormatter()
    184. binaryFormatter.Serialize(InMemory, origin)
    185. InMemory.Seek(0, SeekOrigin.Begin)
    186. Return DirectCast(binaryFormatter.Deserialize(InMemory), T)
    187. End Using
    188. End Function
    189. Shared Function parseToDec(str As String) As Decimal
    190. Dim out As Decimal = 0.00000000
    191. Try
    192. If str.ToUpper().Contains("E") Then
    193. out = Decimal.Parse(str, NumberStyles.Float)
    194. Else
    195. out = Decimal.Parse(str, NumberStyles.AllowDecimalPoint + NumberStyles.AllowParentheses + NumberStyles.AllowThousands)
    196. End If
    197. Catch ex As Exception
    198. MsgBox("Parse-Fehler: " & ex.Message & vbNewLine & "Eingabe: " & str)
    199. End Try
    200. Return out
    201. End Function
    202. End Class
    203. End Namespace



    Unterklasse, welche die Hauptklasse erweitert:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Globalization
    2. Imports Newtonsoft.Json.Linq
    3. Namespace Webmana
    4. Partial Public Class BitcoinAPI
    5. ' --- Custom Propertys --------------------------------------------------------
    6. Private _subscribedToHeartbeat As Boolean = False
    7. Public ReadOnly Property subscribedTo_Heartbeat() As Boolean
    8. Get
    9. Return _subscribedToHeartbeat
    10. End Get
    11. End Property
    12. ' --- Custom Events -----------------------------------------------------------
    13. Public Event HeartbeatSubscribed(sender As Webmana.BitcoinAPI.clHeartbeat)
    14. Public Event HeartbeatUpdated(sender As Webmana.BitcoinAPI.clHeartbeat, e As Webmana.BitcoinAPI.HeartbeatEventArgs)
    15. ' --- Event-Tunneling ---------------------------------------------------------
    16. Private Sub Heartbeat_Subscribed(sender As clHeartbeat) Handles Heartbeat.Subscribed
    17. RaiseEvent HeartbeatSubscribed(sender)
    18. End Sub
    19. Private Sub Heartbeat_Updated(sender As Object, e As HeartbeatEventArgs) Handles Heartbeat.Updated
    20. RaiseEvent HeartbeatUpdated(sender, e)
    21. End Sub
    22. ' --- Custom Extension Class --------------------------------------------------
    23. Public WithEvents Heartbeat As New clHeartbeat(Me)
    24. ' --- API-Functions ---------------------------------------------------
    25. Public Sub subscribeTo_Heartbeat()
    26. If Me._subscribedToHeartbeat = False Then
    27. Dim req As JObject = New JObject(
    28. New JProperty("channel", "heartbeat"),
    29. New JProperty("action", "subscribe")
    30. )
    31. If Me._isConnected = True Then
    32. websocket.Send(req.ToString)
    33. Else
    34. MsgBox("Heartbeat abonnieren: Es besteht keine Server-Verbindung!")
    35. End If
    36. Else
    37. MsgBox("Heartbeat abonnieren: Heartbeat wurde bereits abonniert!")
    38. End If
    39. End Sub
    40. Public Class clHeartbeat
    41. ' Link to Parent-Class
    42. Private parentClass As BitcoinAPI
    43. ' --- Propertys ---------------------------------------------------------------
    44. Private _timestamp As String = ""
    45. Public ReadOnly Property Timestamp() As String
    46. Get
    47. Return _timestamp
    48. End Get
    49. End Property
    50. ' --- Events ------------------------------------------------------------------
    51. Public Event Subscribed(sender As clHeartbeat)
    52. Public Event Updated(sender As clHeartbeat, e As HeartbeatEventArgs)
    53. ' --- Internals ---------------------------------------------------------------
    54. Public Sub New(pClass)
    55. Me.parentClass = pClass
    56. AddHandler parentClass.websocket.MessageReceived, AddressOf Me.socketMessage
    57. AddHandler parentClass.websocket.DataReceived, AddressOf Me.socketDataReceived
    58. End Sub
    59. Private Sub socketMessage(s As Object, e As WebSocket4Net.MessageReceivedEventArgs)
    60. If e.Message.Length > 0 And e.Message.StartsWith("{") Then
    61. socketIncome(JObject.Parse(e.Message))
    62. Else
    63. MsgBox("Unbekannte Nachricht emfangen!" & vbNewLine & vbNewLine & e.Message.ToString())
    64. End If
    65. End Sub
    66. Private Sub socketDataReceived(ss As Object, e As WebSocket4Net.DataReceivedEventArgs)
    67. If e.Data.ToString().Length > 0 And e.Data.ToString().StartsWith("{") Then
    68. socketIncome(JObject.Parse(e.Data.ToString()))
    69. Else
    70. MsgBox("Unbekannte Daten emfangen!" & vbNewLine & vbNewLine & e.Data.ToString())
    71. End If
    72. End Sub
    73. Private Sub socketIncome(jResult As JObject)
    74. If jResult.ContainsKey("channel") Then
    75. If jResult("channel") = "heartbeat" Then
    76. If jResult.ContainsKey("event") Then
    77. Select Case jResult("event")
    78. Case "subscribed"
    79. parentClass._subscribedToHeartbeat = True
    80. RaiseEvent Subscribed(Me)
    81. Case "rejected"
    82. MsgBox("Vorgang abgelehnt: " & jResult("text").ToString)
    83. Case "updated"
    84. setUpdate(jResult)
    85. Case Else
    86. MsgBox("Unbekanntes Event!" & vbNewLine &
    87. " - Channel: " & jResult("channel").ToString & vbNewLine &
    88. " - Event: " & jResult("event").ToString)
    89. End Select
    90. End If
    91. End If
    92. End If
    93. End Sub
    94. Private Sub setUpdate(jResult As JObject)
    95. Try
    96. Dim wasUpdated As Boolean = False
    97. If jResult.ContainsKey("timestamp") Then Me._timestamp = jResult("timestamp") : wasUpdated = True
    98. If wasUpdated = True Then RaiseEvent Updated(Me, New HeartbeatEventArgs(Me._timestamp))
    99. Catch ex As Exception
    100. MsgBox("Fehler im Ticker/Update: " & ex.Message)
    101. End Try
    102. End Sub
    103. ' --- Publics -----------------------------------------------------------------
    104. End Class
    105. Public Class HeartbeatEventArgs
    106. Inherits EventArgs
    107. Private _timestamp As String = ""
    108. Public ReadOnly Property Timestamp() As String
    109. Get
    110. Return _timestamp
    111. End Get
    112. End Property
    113. Public Sub New(ts As String)
    114. Me._timestamp = ts
    115. End Sub
    116. End Class
    117. End Class
    118. End Namespace



    @RodFromGermany kannst du mir anhand meines Codes erklären, wie du das meinst mit der Event-Signatur? Muss ich das sender-Object garnicht übergeben?
    __________________________
    01:
    CLS : SCREEN 12
    02: LINE (0, 20)-(640, 22), 15, BF
    03: ECHO "MFG HASSOWUFF"
    [F5]
    @ErfinderDesRades Ich nehme mal so eine Kette an:
    UserControl1 in einer DLL
    auf
    UserControl2 als TabPage
    auf
    TabControl an GUI, das Event würde dann durch das UserControl2 "durchgetunnelt",
    allerdings passt das dann ganz nicht zur Beschreibung "Hauptklasse".
    @hassowuff Du musst nix übergeben, denn Du wirst nicht bestraft, wenn Du es nicht tust (höchstens mit nem Sechser in Informatik) :D
    Allerdings ist das dann kei "Event" im engeren Sinne, sondern ein allgemeiner Delegate, der nicht mit Handles ... eingerichtet werden kann.
    Events im engeren Sinne, d.h. mit der richtigen Signatur, können in VB.NET mit Handles ... eingerichtet werden.
    Mit .NET-Event-Signatur sägen dann die betreffenden Zeilen Deines Codses so aus:

    VB.NET-Quellcode

    1. Public Event Update(sender as Webmana.BitcoinAPI.clOrderbookL2, e As EventArgs)
    2. '...
    3. RaiseEvent Update(Me, EventArgs.Empty)
    4. ' ...
    5. Private Sub API_OrderbookL2Updated(sender as object, e As EventArgs) Handles API.OrderbookL2.Updated
    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 Vereinfacht dargestellt das hier:

    VB.NET-Quellcode

    1. Public Class clHauptklasse
    2. Public WithEvents refToUnterklasse As New clUnterklasse()
    3. Public Event Ereignis1(MyParams As Object)
    4. Public Sub New()
    5. End Sub
    6. Private Sub Ereignis1_Handler(MyParams As Object) Handles refToUnterklasse.Ereignis1
    7. RaiseEvent Ereignis1(MyParams) ' In der Haupt-/Übergeordneten Klasse: Abfangen und neuauslösen des Ereignisses
    8. End Sub
    9. Public Class clUnterklasse
    10. Public Event Ereignis1(MyParams As Object)
    11. Public Sub New()
    12. RaiseEvent Ereignis1("Irgendwelche Paramter") ' In der Kind-/Untergeordneten Klasse:Ursprüngliches Auslösen des Ereignisses
    13. End Sub
    14. End Class
    15. End Class


    Meine Definition: Also das Abfangen und neuauslösen des Events in einer Übergeordneten Klasse. Ist das falsch, oder war das unverständlich? Klär mich auf, wenn ich da einfach nur Bockmist baue ;)

    Wofür?: (Link zum Vollbild: ibb.co/pdTsdw4)
    __________________________
    01:
    CLS : SCREEN 12
    02: LINE (0, 20)-(640, 22), 15, BF
    03: ECHO "MFG HASSOWUFF"
    [F5]

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

    hassowuff schrieb:

    Meine Definition: Also das Abfangen und neuauslösen des Events in einer Übergeordneten Klasse. Ist das falsch, oder war das unverständlich? Klär mich auf, wenn ich da einfach nur Bockmist baue
    Nein, so erklärt ist nix falsches oder unverständliches dran.
    Und auch kein Bockmist, sondern kann man so machen.
    Alternativ kann man auch machen wie in post#2 gesagt.

    Auf deine unorthodoxe Event-Signatur wurdest du ja schon angesprochen.