跨线程操作无效:控件 '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))
我正在使用电报 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))