C# 将数据从类传递到表单列表框|聊天客户端

C# 将数据从类传递到表单列表框|聊天客户端,c#,winforms,tcp,chat,interaction,C#,Winforms,Tcp,Chat,Interaction,我目前正在开发一个聊天程序。它包含一个窗体(MainWindow)和一个类(TCPServerConnector)。 主窗口是包含两个文本框、两个按钮和一个列表框的UI 在第一个文本框中,您必须写入要连接的服务器ip,然后单击“连接”按钮。第二个文本框包含您的书面文本,第二个按钮发送此文本。列表框应该显示程序从服务器收到的所有聊天/文本,但我无法让它工作 主窗体初始化TCPServerConnector的对象,并将IP和文本传递给它。但是当你收到一些文本时,班级必须将收到的文本传递给表单 我尝试

我目前正在开发一个聊天程序。它包含一个窗体(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谢谢