C# 将数据从类传递到表单列表框|聊天客户端
我目前正在开发一个聊天程序。它包含一个窗体(MainWindow)和一个类(TCPServerConnector)。 主窗口是包含两个文本框、两个按钮和一个列表框的UI 在第一个文本框中,您必须写入要连接的服务器ip,然后单击“连接”按钮。第二个文本框包含您的书面文本,第二个按钮发送此文本。列表框应该显示程序从服务器收到的所有聊天/文本,但我无法让它工作 主窗体初始化TCPServerConnector的对象,并将IP和文本传递给它。但是当你收到一些文本时,班级必须将收到的文本传递给表单 我尝试使用委托(以前从未使用过委托),但这并没有解决我的问题,我只是遇到了一些关于交叉线程的例外 还创建了一个新的主窗口实例,因为它没有引用主窗体的旧实例 我已经添加了下面这些类的代码,希望有人能处理我的问题;)C# 将数据从类传递到表单列表框|聊天客户端,c#,winforms,tcp,chat,interaction,C#,Winforms,Tcp,Chat,Interaction,我目前正在开发一个聊天程序。它包含一个窗体(MainWindow)和一个类(TCPServerConnector)。 主窗口是包含两个文本框、两个按钮和一个列表框的UI 在第一个文本框中,您必须写入要连接的服务器ip,然后单击“连接”按钮。第二个文本框包含您的书面文本,第二个按钮发送此文本。列表框应该显示程序从服务器收到的所有聊天/文本,但我无法让它工作 主窗体初始化TCPServerConnector的对象,并将IP和文本传递给它。但是当你收到一些文本时,班级必须将收到的文本传递给表单 我尝试
主要形式:
public partial class MainWindow : Form
{
public MainWindow()
{
InitializeComponent();
}
TCPServerConnector TestConnection = new TCPServerConnector();
private void Form1_Load(object sender, EventArgs e)
{
}
private void srvConnect_Click(object sender, EventArgs e)
{
TestConnection.ConnectToServer(srvConnectionIP.Text.ToString());
}
private void srvSend_Click(object sender, EventArgs e)
{
TestConnection.SendEnteredString(srvTextToSend.Text.ToString());
}
private void FormMain_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
TestConnection.CloseConnection();
}
}
class TCPServerConnector
{
private Socket m_sock;
private byte[] m_byBuff = new byte[256];
public void ConnectToServer(string ServerAddress)
{
try
{
if (m_sock != null && m_sock.Connected)
{
m_sock.Shutdown(SocketShutdown.Both);
System.Threading.Thread.Sleep(10);
m_sock.Close();
}
m_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint epServer = new IPEndPoint(IPAddress.Parse(ServerAddress), 399);
m_sock.Blocking = false;
AsyncCallback onconnect = new AsyncCallback(OnConnect);
m_sock.BeginConnect(epServer, onconnect, m_sock);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void OnConnect(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
if (sock.Connected)
SetupRecieveCallback(sock);
else
MessageBox.Show("Unable to establish connection");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void OnRecievedData(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
int nBytesRec = sock.EndReceive(ar);
if (nBytesRec > 0)
{
string sRecieved = Encoding.ASCII.GetString(m_byBuff, 0, nBytesRec);
MessageBox.Show(sRecieved); //TO SHOW IF SOMETHING HAPPENED. HERE IS MY PROBLEM
SetupRecieveCallback(sock);
}
else
{
Console.WriteLine("Client {0}, disconnected", sock.RemoteEndPoint);
sock.Shutdown(SocketShutdown.Both);
sock.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void SetupRecieveCallback(Socket sock)
{
try
{
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
sock.BeginReceive(m_byBuff, 0, m_byBuff.Length, SocketFlags.None, recieveData, sock);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void SendEnteredString(string EnteredData)
{
if (m_sock == null || !m_sock.Connected)
{
MessageBox.Show("You have to be connected to send something.");
return;
}
try
{
Byte[] byteDateLine = Encoding.ASCII.GetBytes(EnteredData.ToCharArray());
m_sock.Send(byteDateLine, byteDateLine.Length, 0);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void CloseConnection()
{
if (m_sock != null && m_sock.Connected)
{
m_sock.Shutdown(SocketShutdown.Both);
m_sock.Close();
}
}
}
在方法“onReceiveDdata”中,我添加了一个Messagebox来显示收到的文本,因为现在,我无法将其添加到表单列表框中 TCPServerConnector类:
public partial class MainWindow : Form
{
public MainWindow()
{
InitializeComponent();
}
TCPServerConnector TestConnection = new TCPServerConnector();
private void Form1_Load(object sender, EventArgs e)
{
}
private void srvConnect_Click(object sender, EventArgs e)
{
TestConnection.ConnectToServer(srvConnectionIP.Text.ToString());
}
private void srvSend_Click(object sender, EventArgs e)
{
TestConnection.SendEnteredString(srvTextToSend.Text.ToString());
}
private void FormMain_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
TestConnection.CloseConnection();
}
}
class TCPServerConnector
{
private Socket m_sock;
private byte[] m_byBuff = new byte[256];
public void ConnectToServer(string ServerAddress)
{
try
{
if (m_sock != null && m_sock.Connected)
{
m_sock.Shutdown(SocketShutdown.Both);
System.Threading.Thread.Sleep(10);
m_sock.Close();
}
m_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint epServer = new IPEndPoint(IPAddress.Parse(ServerAddress), 399);
m_sock.Blocking = false;
AsyncCallback onconnect = new AsyncCallback(OnConnect);
m_sock.BeginConnect(epServer, onconnect, m_sock);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void OnConnect(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
if (sock.Connected)
SetupRecieveCallback(sock);
else
MessageBox.Show("Unable to establish connection");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void OnRecievedData(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
int nBytesRec = sock.EndReceive(ar);
if (nBytesRec > 0)
{
string sRecieved = Encoding.ASCII.GetString(m_byBuff, 0, nBytesRec);
MessageBox.Show(sRecieved); //TO SHOW IF SOMETHING HAPPENED. HERE IS MY PROBLEM
SetupRecieveCallback(sock);
}
else
{
Console.WriteLine("Client {0}, disconnected", sock.RemoteEndPoint);
sock.Shutdown(SocketShutdown.Both);
sock.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void SetupRecieveCallback(Socket sock)
{
try
{
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
sock.BeginReceive(m_byBuff, 0, m_byBuff.Length, SocketFlags.None, recieveData, sock);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void SendEnteredString(string EnteredData)
{
if (m_sock == null || !m_sock.Connected)
{
MessageBox.Show("You have to be connected to send something.");
return;
}
try
{
Byte[] byteDateLine = Encoding.ASCII.GetBytes(EnteredData.ToCharArray());
m_sock.Send(byteDateLine, byteDateLine.Length, 0);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void CloseConnection()
{
if (m_sock != null && m_sock.Connected)
{
m_sock.Shutdown(SocketShutdown.Both);
m_sock.Close();
}
}
}
原因:由于您在一个线程上创建GUI,并在另一个线程上访问它,因此您将获得跨线程异常。这在c#中是不允许的 你需要像这样改变你的路线
MethodInvoker method = delegate
{
MessageBox.Show(sRecieved);
};
if (InvokeRequired)
BeginInvoke(method);
else
method.Invoke();
在连接器类中创建事件DataReceived,并在收到数据时引发它:
public class TCPServerConnector
{
public event Action<string> DataReceived; // event
public void OnRecievedData(IAsyncResult ar)
{
try
{
Socket sock = (Socket)ar.AsyncState;
int nBytesRec = sock.EndReceive(ar);
if (nBytesRec > 0)
{
string sRecieved = Encoding.ASCII.GetString(m_byBuff, 0, nBytesRec);
if (DataReceived != null) // check if subscribed
DataRecieved(sRecieved); // raise event with data
SetupRecieveCallback(sock);
}
else
{
Console.WriteLine("Client {0}, disconnected", sock.RemoteEndPoint);
sock.Shutdown(SocketShutdown.Both);
sock.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
// rest of code is same
}
注意:您可以对事件使用
EventHandler
委托类型(与Microsoft一样),并创建受保护的方法OnDataReceived(字符串数据)
来引发事件。但是为了简单起见,我使用了Action
delegate 我已经将你的答案添加到我的代码中,意识到它不起作用。所以我仔细研究了使用Microsofts MSDN库调用。对这个结构稍作修改:this.Invoke((MethodInvoker)委托{TestConnection_DataReceived(data);})代码>而不是:Invoke((MethodInvoker)(()=>TestConnection_DataReceived(data))代码>它在.NETFramework 2上工作。在版本3及更高版本中,它的工作方式与您建议的相同:D谢谢