跨线程操作无效:控件 'RichTextBox' 从创建它的线程以外的线程访问

Cross-thread operation not valid: Control 'RichTextBox' accessed from a thread other than the thread it was created on

我正在使用电报 API 向客户端发送消息。 我使用的代码是:

Imports System.Threading
Imports Telegram.Bot
Imports Telegram.Bot.Extensions.Polling
Imports Telegram.Bot.Types
Imports Telegram.Bot.Types.Enums
    
Public Class form1
    Private Async Function HandleUpdateAsync(botClient As ITelegramBotClient,
                                             update As Update,
                                             cancellationToken As CancellationToken) As Task
    
        If update.Message IsNot Nothing Then
            If Not String.IsNullOrEmpty(update.Message.Text) Then
                Select Case update.Message.Text
                    Case "/0"
                         Await botClient.SendTextMessageAsync("chatid", RichTextBox1.Text)
                    Case "/star2t"
                        Await botClient.SendTextMessageAsync("chatid", "text")
                End Select
            End If
        End If
    End Function
    
    Private Function HandleErrorAsync(botClient As ITelegramBotClient,
                                      exception As Exception,
                                      cancellationToken As CancellationToken) As Task
        Console.WriteLine(exception)
        Return Task.CompletedTask
    End Function
    
    Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'invio messaggio 
        Dim bot = New TelegramBotClient("token id")
        Await bot.SendTextMessageAsync("chatid", "Test")
    End Sub
    
    Private Sub form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim bot = New TelegramBotClient("My id")
  
        Dim cts = New CancellationTokenSource()
        Dim options = New ReceiverOptions With {
            .AllowedUpdates = Array.Empty(Of UpdateType)()
        }
        bot.StartReceiving(updateHandler:=AddressOf HandleUpdateAsync, errorHandler:=AddressOf HandleErrorAsync, options, cts.Token)
        Console.ReadLine()
    End Sub
End Class

正在发送消息

Await botClient.SendTextMessageAsync("chatid", "text")

但它没有发送

Await botClient.SendTextMessageAsync("chatid", Richtextbox5.text)

我在运行时或调试时没有收到任何错误,但在调试时检查 VS 上的即时 Window 我发现存在跨线程问题:

exception thrown: 'System.InvalidOperationException' in System.Windows.Forms.dll
System.InvalidOperationException: Cross-thread operation not valid: Control 'RichtextBox5' accessed from a thread other than the thread it was created on
in System.Windows.Forms.Control.get_Handle()
in System.Windows.Forms.RichTextBox.StreamOut(Stream data, Int32 flags, Boolean includeCrLfs)
in System.Windows.Forms.RichTextBox.StreamOut(Int32 flags)
in System.Windows.Forms.RichTextBox.get_Text()
in HotBit_APIs.Form1.VB$StateMachine_17_HandleUpdateAsync.MoveNext()
in C:\Users\Mattia\source\repos\HotBit APIs\HotBit APIs\Form1.vb:line 81

我一直在网上寻找解决方案,我偶然发现了这段代码

Private Sub UpdateTextBox(text As String)
    If TextBox1.InvokeRequired Then
        'We are on a secondary thread.
        TextBox1.Invoke(New Action(Of String)(AddressOf UpdateTextBox), text)
    ecc

yourForm.Invoke(new Action(() => {GUI code here}))

但我不知道如何使用我的代码来实现。 知道我该怎么做吗?

您不能仅从任何线程访问 UI 元素 - 它必须在 UI 线程上。使用这样的处理程序,您不能假设您在 UI 线程上,实际上您应该假设您可能不在。确保正确访问 UI 控件的方法是,在访问它之前始终检查是否 InvokeRequired

Dim text As String
If control.InvokeRequired Then
    control.Invoke(Sub() text = control.Text)
Else
    text = control.Text
End If

对于您的情况,问题出在 HandleUpdateAsync。代码行

Await botClient.SendTextMessageAsync("chatid", RichTextBox1.Text)

可以改为

Dim text As String
If RichTextBox1.InvokeRequired Then
    RichTextBox1.Invoke(Sub() text = RichTextBox1.Text)
Else
    text = RichTextBox1.Text
End If
Await botClient.SendTextMessageAsync("chatid", text)

执行此操作的公认方法不是像那样内联在代码中。您的 google 搜索已找到它。一般是这样的

Private Function GetRichTextBox1Text() As String
    If RichTextBox1.InvokeRequired Then
        Return RichTextBox1.Invoke(AddressOf GetRichTextBox1Text)
    Else
        Return RichTextBox1.Text
    End If
End Function
Await botClient.SendTextMessageAsync("chatid", GetRichTextBox1Text())

没有人愿意一直这样做。您可以像这样在模块中编写扩展方法(用于操作和简单功能),当然您可以根据这些方法推断任意数量的参数

<Extension(), DebuggerHidden()>
Public Sub InvokeIfRequired(control As Control, action As MethodInvoker)
    If control.InvokeRequired Then control.Invoke(action) Else action()
End Sub
' No parameters
<Extension(), DebuggerHidden()>
Public Function InvokeIfRequired(Of TR)(control As Control, func As Func(Of TR)) As TR
    If control.InvokeRequired Then
        Return control.Invoke(func)
    Else
        Return func.Invoke()
    End If
End Function
' One parameter
<Extension(), DebuggerHidden()>
Public Function InvokeIfRequired(Of T1, TR)(control As Control, func As Func(Of T1, TR), arg1 As T1) As TR
    If control.InvokeRequired Then
        Return CType(control.Invoke(func, arg1), TR)
    Else
        Return func.Invoke(arg1)
    End If
End Function
' n parameters can be extrapolated...

在你的情况下,使用函数

Await botClient.SendTextMessageAsync("chatid", RichTextBox1.InvokeIfRequired(Function() RichTextBox1.Text))