2011-05-14 39 views
1

我创造了我的游戏(网络时,服务器/客户端的风格)聊天界面,我遇到了一个小问题...如何解决跨线程操作

它的工作方式...我有用于SERVER(frmServer)和CLIENTS(frmClient)的表单,它们都有一个LISTBOX(lbChat),我在其中输入(lbChat.Items.Add(字符串))文本作为用户输入它 - 本质上是一个chatbox。

因此,我们使用CLIENT作​​为示例(因为它更简单,概念在客户端和服务器的情况下都是相同的)... 客户端窗体(frmClient)创建一个用于侦听聊天消息(通过TCP) - 所以我做的是通过列表框本身(lbChat) (我认为)解决了我在聊天消息到达时写入列表框的问题(并且当然被线程捕获而不是frmClient)... 现在,在调试代码时,我得到以下异常:当我的线程尝试写入frmClient的列表框(lbChat) 一般异常:System.InvalidOperationException:跨线程操作无效:控制'lbChat'从其创建的线程以外的线程访问。

所以现在的问题是我该如何解决这个跨线程异常?如何从我的监听器线程(并且在场中会有多个,每个客户端一个)将信息(聊天文本)传递给表单上的集中式列表框(lbChat)? 我需要某种方法来传输信息,同时也减少了碰到争用问题的机会(我是否需要使用ReaderWriterLock?),事情是我不知道如何完成这项任务(我想简单地通过列表框会让我写它在每个线程)...

任何想法,提示和帮助,将不胜感激,谢谢 这是客户端代码

Imports System.Net.Sockets 
Imports System.Windows.Forms 
Imports System.IO 
Imports System.Threading 

Public Class recieve 

Private reader As BinaryReader 
Private message As String = "" 
Private frmObject As frmMain 
Private readthred As Thread 
Private Delegate Sub af(ByVal item As String) 
Public Sub fun(ByVal item As String) 
    If (frmMain.ListBox1.InvokeRequired()) Then 
     frmMain.ListBox1.Invoke(New af(AddressOf fun)) 
     frmMain.ListBox1.Items.Add(item) 
    Else 
     frmMain.ListBox1.Items.Add(item) 

    End If 
End Sub 
Public Sub New(ByVal frmObject As frmMain) 
    MyBase.New() 
    Me.frmObject = frmObject 
    readthred = New Thread(AddressOf runClinet) 
    readthred.SetApartmentState(ApartmentState.STA) 
    readthred.Start() 

End Sub 



Public Sub runClinet() 
    Dim client As TcpClient 
    Try 
     client = New TcpClient() 
     client.Connect("127.0.0.1", 5234) 
     reader = New BinaryReader(client.GetStream()) 
     Try 
      Dim Path As String 
      Path = reader.ReadString 
      frmMain.ListBox1.SelectedItem = Path 

      frmObject.Playlist.SelectedItem = frmObject.ListBox1.SelectedItem 
      frmMain.AxWindowsMediaPlayer1.URL = Path 
      frmObject.ListBox1.Items.Add(Path) 
      frmObject.Playlist.Items.Add(Path) 
      Try 
       While True 
        Path = reader.ReadString 
        Select Case Path 
         Case "1" 
          frmObject.AxWindowsMediaPlayer1.Ctlcontrols.pause() 
         Case "2" 
          frmObject.AxWindowsMediaPlayer1.Ctlcontrols.play() 
         Case "3" 
          frmObject.AxWindowsMediaPlayer1.Ctlcontrols.stop() 
        End Select 
       End While 
      Catch ex As Exception 
      End Try 
     Catch inputoutputException As IOException 
     Finally 
     End Try 
     Try 
      frmObject.AxWindowsMediaPlayer1.Ctlcontrols.stop() 
      reader.Close() 
      client.Close() 
     Catch exx As Exception 
     End Try 
    Catch inputoutputException As IOException 
    End Try 
End Sub 

末级

+0

[Cross-thread operation not valid](http:// stackoverflow。 com/questions/5624033/cross-thread-operation-not-valid) – 2011-05-14 18:27:20

回答

2

致电Me.BeginInvoke(...)传递一个指向该函数的委托应该在UI线程上调用。

例如为:

Me.BeginInvoke(New MyDelegate(AddressOf DelegateMethod), parameterArray) 

BeginInvoke和调用传递一个代表被调用到UI线程。

编辑

在您访问列表框,播放列表和形式本身runClient方法。此方法在其他线程上运行,因此所有这些调用都必须使用BeginInvoke或Invoke切换到UI线程。

+0

我已经试过,但did'nt work – kelly 2011-05-14 18:00:30

+0

只需添加到,你可以从表单中检查'Me.InvokeRequired',看看它是不是_not_在UI线程('True')上。如果不是,那么你必须'调用'调用来把自己放在UI线程上。如果是,那么你可以处理。 – pickypg 2011-05-14 18:01:04

+0

'如果(frmMain.ListBox1.InvokeRequired()),然后 frmMain.ListBox1.Invoke(新的AF(AddressOf乐趣)) frmMain.ListBox1.Items.Add(项目) 否则 frmMain.ListBox1.Items.Add(项目) End If'' that that you're talking about but it dos'nt work – kelly 2011-05-14 18:03:40