C# Windows 窗体多线程处理从另一个类事件更新窗体控件

本文关键字:窗体 事件 更新 控件 Windows 多线程处理 另一个 | 更新日期: 2023-09-27 17:55:21

>onrecvdChanged是(服务器类)一旦发生的事件,我希望它更改form1类的label1的文本。我被困在这里很久了。我尝试了一些技巧,但出现交叉线程异常。

namespace TCPServerTutorial
{
    public partial class Form1 : Form
    {
        Server a;
        public Form1()
        {
            InitializeComponent();
            label1.Text = "Ready";
            a=new Server(this);
        }
        private void Start_btn_Click(object sender, EventArgs e)
        {
            a.StartTcpServer();
            label1.Text = "Listening...";
        }
        private void Stop_Btn_Click(object sender, EventArgs e)
        {
            a.StopListenForClients();
            label1.Text = "Stopped...";
        }
    }

    class Server
    {
        public event EventHandler recvdChanged;
        private TcpListener tcpListener;
        private Thread listenThread;
        private string recvd;
        Form1 _f1parent;
        public Server(Form1 par)
        {
            _f1parent = par;
        }
        public string getsetrecvd
        {
            get { return this.recvd; }
            set
            {
                this.recvd = value;
                if (this.recvdChanged != null)
                    this.recvdChanged(this, new EventArgs());
            }
        }
        public void StartTcpServer()
        {
            this.tcpListener = new TcpListener(IPAddress.Any, 3000);
            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.Start();
        }
        private void ListenForClients()
        {
            this.tcpListener.Start();
            while (true)
            {
                //blocks until a client has connected to the server
                TcpClient client = this.tcpListener.AcceptTcpClient();
                if(client.Connected)
                {
                    MessageBox.Show(client.Client.RemoteEndPoint + " Has Connected.");
                }
                //create a thread to handle communication 
                //with connected client
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                clientThread.Start(client);
            }
        }
        public void StopListenForClients()
        {
            tcpListener.Stop();
        }
        private void HandleClientComm(object client)
        {
            TcpClient tcpClient = (TcpClient)client;
            NetworkStream clientStream = tcpClient.GetStream();
            recvdChanged += new EventHandler(onrecvdChanged);
            byte[] message = new byte[4096];
            int bytesRead;
            Form1 p = new Form1();
            while (true)
            {
                bytesRead = 0;
                try
                {
                    //blocks until a client sends a message
                    bytesRead = clientStream.Read(message, 0, 4096);
                }
                catch
                {
                    //a socket error has occured
                    break;
                }
                if (bytesRead == 0)
                {
                    //the client has disconnected from the server
                    break;
                }
                //message has successfully been received
                ASCIIEncoding encoder = new ASCIIEncoding();
                getsetrecvd=encoder.GetString(message, 0, bytesRead);
                if (recvd != "e")
                {
                }
                else
                {
                    break;
                }
            }
            tcpClient.Close();
        }
        void onrecvdChanged(object sender, EventArgs e)
        {
            MessageBox.Show("event: " + recvd);
        }
    }
}

C# Windows 窗体多线程处理从另一个类事件更新窗体控件

您已经有一个在字符串更改时触发的事件,recvdChanged . 只需让窗体向该事件添加一个事件处理程序,然后调用 UI 线程:

public Form1()
{
    InitializeComponent();
    label1.Text = "Ready";
    a=new Server(this);
    a.recvdChanged += (_,args) => Invoke(new MethodInvoker(
        ()=>label1.Text = a.getsetrecvd));
}
不需要

Server 类本身内使用该事件的事件处理程序。

交叉线程异常通常通过使用 Invoke 来修复。

我发现最简单的方法是使用 MethodInvoker 强制转换和 Lambda 表达式......像这样:

Invoke((MethodInvoker)( () => Form1.Label1.Text = "some string" ) );