首页 > 解决方案 > 从其他线程 (VBNET) 的异步事件 (websocket) 更新表单

问题描述

在收到来自另一个类的异步触发事件的消息后,我正在尝试更新表单上的标签,但到目前为止没有任何效果。

好吧,一个有效的方法是在主线程上添加一个计时器,它每 200 毫秒使用另一个类的公共变量更新标签。但必须有其他方法。

我尝试使用调用方法,但这也不起作用。

我错过了什么/做错了什么?

编辑:下面的函数被调用:

Await SubscribeToWebsocketEvents(creds)

功能:

Public Shared Async Function SubscribeToWebsocketEvents(ByVal creds As Credentials) As Task
    Dim socket = New CoinbaseProWebSocket(New WebSocketConfig With {
    .ApiKey = creds.ApiKey,
    .Secret = creds.ApiSecret,
    .Passphrase = creds.ApiPassphrase,
    .SocketUri = "wss://ws-feed-public.sandbox.pro.coinbase.com"
})

    WriteLine(">> Connecting websocket...")

    Dim result = Await socket.ConnectAsync()

    If Not result.Success Then Throw New Exception("Connect error.")
    WriteLine(">> Connected.")

    AddHandler socket.RawSocket.Closed, (AddressOf Websocket_Closed)
    AddHandler socket.RawSocket.Error, (AddressOf Websocket_Error)
    AddHandler socket.RawSocket.MessageReceived, (AddressOf Websocket_MessageReceived)

    Dim Subsc = New Subscription

    Subsc.ProductIds.AddRange({"BTC-EUR", "BTC-USD"})
    Subsc.Channels.Add("ticker")
    Subsc.Channels.Add("matches")

    WriteLine(">> Subscribing to events...")
    Await socket.SubscribeAsync(Subsc)
    WriteLine(">> Subscribed.")
End Function

事件:

Private Shared Sub Websocket_MessageReceived(ByVal sender As Object, ByVal e As WebSocket4Net.MessageReceivedEventArgs)
    WriteLine("Message received.")

    Dim msg = Nothing, hb As HeartbeatEvent = Nothing, tk As TickerEvent = Nothing

    Form1.BitcoinPriceLabel.Text = "Test to see if I can edit the label"

    If WebSocketHelper.TryParse(e.Message, msg) Then
        If CSharpImpl.__Assign(hb, TryCast(msg, HeartbeatEvent)) IsNot Nothing Then
            '     WriteLine($"Sequence: {hb.Sequence}, Last Trade Id: {hb.LastTradeId}")
        End If
        If CSharpImpl.__Assign(tk, TryCast(msg, TickerEvent)) IsNot Nothing Then
            If tk.ProductId = "BTC-EUR" Then
                WriteLine($"Coin: {tk.ProductId}, Last value: {tk.Price}, BestAsk: {tk.BestAsk}")
            End If
        End If
    End If
End Sub

标签: vb.netmultithreadingvariableswebsocket

解决方案


问题是您Form1在辅助线程上使用默认实例。默认实例是特定于线程的,因此您更新的实例不是您显示的实例。阅读内容以获取更多信息。

解决方案是在 UI 线程上调用一个方法,然后您使用的默认实例将与您显示的相同。如果您在一个不是表单或其他控件的类中,则使用SynchronizationContext该类的方法是,例如

Private context As SynchronizationContext = SynchronizationContext.Current

'This method is executed on a secondary thread.
Private Sub BackgroundMethod()
    context.Post(AddressOf ForegroundMethod, Nothing)
End Sub

'This method is executed on the UI thread.
Private Sub ForegroundMethod(state As Object)
    'Update the UI here.
End Sub

您需要在 UI 线程上创建该类型的实例,然后它获得的当前上下文将是 UI 线程的上下文。该上下文用于稍后将委托发布到该线程。您为其创建委托的方法必须有一个类型为 的参数Object。当您调用Post将所需的任何数据传递给该参数时,然后在发布的方法中将其转换为适当的类型。在您的情况下,该方法可能如下所示:

Private Sub SetForm1BitcoinPriceLabelText(text As Object)
    Form1.BitcoinPriceLabel.Text = text
End Sub

你可以这样称呼它:

context.Post(AddressOf SetForm1BitcoinPriceLabelText, "Test to see if I can edit the label")

推荐阅读