简体   繁体   English

无法在跨线程操作VB.NET中附加RichTextBox文本

[英]Unable to append RichTextBox text in Cross-Thread operation VB.NET

I'am coding a Multi-Threaded TCP echo server, but the problem is when i call UpdateMessage from ClientHandler class, the RichTextBox's text is not appending. 我正在编码一个多线程TCP回显服务器,但是问题是当我从ClientHandler类调用UpdateMessage时,RichTextBox的文本未追加。

This is the Form1 class that containts the RichTextBox1 这是包含RichTextBox1的Form1类

Public Class Form1 公开课表格1

Const PORT As Integer = 1234 'The port number on which the server will listen for connection.
Dim ServerSocket As New TcpListener(PORT) 'The Server Socket that will listen for connections on specified port number.

Dim Link As TcpClient 'The Socket that will handle the client.

Dim NumberOfClients As Integer = 0 'The total number of clients connected to the server.


Dim myThread As Thread 'The thread on which the server will handle the client


Dim sc As SynchronizationContext = SynchronizationContext.Current

Public Clienthandler As ClientHandler

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnStart.Click
    ServerSocket.Start()
    ' UpdateMessage("Server started..")


    myThread = New Thread(AddressOf AcceptClients) 'Handle the client in a different thread
    myThread.Start()


    btnStart.Text = "Started!"
    btnStart.Enabled = False

End Sub




Private Sub AcceptClients()


    'Keep accepting and handling the clients.
    While (True)
        Link = ServerSocket.AcceptTcpClient() 'Accept the client and let the Socket deal with it.
        NumberOfClients = NumberOfClients + 1 'update the total number of clients

        Dim ClientAddress As String = Link.Client.RemoteEndPoint.ToString

        '  UpdateMessage("Client number " & NumberOfClients & " connected from " & ClientAddress)


        Clienthandler = New ClientHandler
        Clienthandler.StartClientThread(Link, NumberOfClients)



        Me.sc.Post(AddressOf Clienthandler.UpdateMessage, "Client number " & NumberOfClients & " connected from " & ClientAddress)

    End While

    'close the sockets

    Link.Close() 'close the Socket.
    ServerSocket.Stop() 'Stop the Server Socket.

End Sub

End Class 末级

And here is the ClientHandler class: 这是ClientHandler类:

Public Class ClientHandler 公共类ClientHandler

Private Link As TcpClient
Private ClientNumber As Integer
Dim NumberOfMessages As Integer = 0 'The number of messages that client has sent.
Dim Stream As NetworkStream 'The stream being used for sending/receiving data over Socket.


Dim scHandler As SynchronizationContext = SynchronizationContext.Current

Public Sub StartClientThread(Link As TcpClient, ClientNumber As Integer)

    'Initialize the class variables with the arguments passed in StartClient 

    Me.Link = Link
    Me.ClientNumber = ClientNumber



    'Start the thread

    Dim ClientThread As New Thread(AddressOf Chat)
    ClientThread.Start()

    UpdateMessage("Thread for client " & ClientNumber & " started!")



End Sub

Public Sub UpdateMessage2(Message As String) 公共子UpdateMessage2(消息为字符串)

    Me.scHandler.Post(AddressOf UpdateMessage2, Message)
End Sub
Public Sub UpdateMessage(Message As String)

    Message = vbNewLine & Trim(Message)

    If Message.Length < 1 Then
        Message = "empty"
    End If

    MessageBox.Show("Updating message!" & vbNewLine & Message)


    Form1.RichTextBox1.AppendText(Message)





End Sub

The same problem still exits, the RichTextBox is being updated from UI Thread only. 仍然存在相同的问题,仅从UI线程更新RichTextBox。

To be a bit more specific than Hans Passant, using the form name where an object is expected makes use of the default instance of the form, which is an instance that the system creates and manages for you. 与Hans Passant相比,它更具体一些,在期望对象的表单名称中使用了表单的默认实例,该实例是系统为您创建和管理的实例。 The default instance is thread-specific though, which means that there is one default instance per thread. 不过,默认实例是特定于线程的,这意味着每个线程有一个默认实例。 If you use the default instance in a secondary thread then you are using a different object to the one that you displayed on the UI thread. 如果在辅助线程中使用默认实例,则使用的对象与UI线程上显示的对象不同。 You might read a bit more about default instances here: 您可以在此处阅读有关默认实例的更多信息:

http://jmcilhinney.blogspot.com.au/2009/07/vbnet-default-form-instances.html http://jmcilhinney.blogspot.com.au/2009/07/vbnet-default-form-instances.html

You need to somehow marshal a method call back to the UI thread and then update the existing form instance on that thread. 您需要以某种方式将方法调用编组回UI线程,然后更新该线程上的现有表单实例。 There are a couple of ways that can be done: 有两种方法可以完成:

  1. Have access to the existing form object and call its Invoke method. 可以访问现有的表单对象并调用其Invoke方法。
  2. Use the SynchronizationContext class to marshal the method call to the UI thread and then use the default instance. 使用SynchronizationContext类封送对UI线程的方法调用,然后使用默认实例。
Class myClass
    Friend TB As TextBox
    Class myThread
        ' ...
    End Class
End Class

Class Form1
    Overrides Sub OnLoad
        _tcpClient = New myClass
        Controls.Add(_tcpClient.TB)
        _tcpClient.doSomething()
    End Sub
End Class

like that, as per my comments. 这样,根据我的评论。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM