vb.net - 从其他线程 (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
解决方案
问题是您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")
推荐阅读
- java - 将Java 类作为其余模板的主体传递
- python - 模型表格未保存
- java - 无法使用 Java 中的 In 子句从 DB 获取记录(Spring 存储库)
- spring-boot - 无法使用传入消息端点处理程序详细信息调用侦听器方法:rabbitMQ
- python - 从卷积网络中删除 Sequential 后,我得到:“TypeError:'Tensor' object is not callable”
- typescript - 是否可以将元组的键映射到数字文字的联合?
- c# - C# 仅使用 do while 以 2 个不同的间隔打印数字
- ios - 在 ViewController 出现之前加载数据/图形/背景的方法
- javascript - 剑道网格截断小数
- eclipse - Eclipse,mvn eclipse:clean eclipse:eclipse,错误:找不到或加载主类