如何在 GUI 标签中显示异步任务的结果?

How to show a result from an async task in GUI label?

我创建客户端应用程序以从服务器读取消息。客户端应用程序有 class SocketClient,它具有 ReadDataAsync() 函数,可以像这样从服务器读取消息。

namespace SocketAsync
{
    public class SocketClient
    {
        IPAddress mServerIPAddress;
        int mServerPort;
        TcpClient mClient;


        public SocketClient()
        {
            mClient = null;
            mServerPort = -1;
            mServerIPAddress = null;
        }

        public IPAddress ServerIPAddress
        {
            get
            {
                return mServerIPAddress;
            }
        }

        public int ServerPort
        {
            get
            {
                return mServerPort;
            }
        }

        public bool SetServerIPAddress(string _IPAddressServer)
        {
            IPAddress ipaddr = null;

            if (!IPAddress.TryParse(_IPAddressServer, out ipaddr))
            {
                Debug.WriteLine("Invalid server IP supplied.");
                return false;
            }

            mServerIPAddress = ipaddr;

            return true;
        }

        public bool SetPortNumber(string _ServerPort)
        {
            int portNumber = 0;

            if (!int.TryParse(_ServerPort.Trim(), out portNumber))
            {
                Debug.WriteLine("Invalid port number supplied, return.");
                return false;
            }

            if (portNumber <= 0 || portNumber > 65535)
            {
                Debug.WriteLine("Port number must be between 0 and 65535.");
                return false;
            }

            mServerPort = portNumber;

            return true;
        }

        public async Task ConnectToServer()
        {
            if (mClient == null)
            {
                mClient = new TcpClient();
            }

            try
            {
                await mClient.ConnectAsync(mServerIPAddress, mServerPort);
                Debug.WriteLine(
                        string.Format("Connected to server IP/Port: {0} / {1}",
                    mServerIPAddress, mServerPort));

                ReadDataAsync(mClient);
            }
            catch (Exception excp)
            {
                Console.WriteLine(excp.ToString());
                throw;
            }
        }

        private async Task ReadDataAsync(TcpClient mClient)
        {
            try
            {
                StreamReader clientStreamReader = new StreamReader(mClient.GetStream());
                char[] buff = new char[64];
                int readByteCount = 0;

                while (true)
                {
                    readByteCount = await clientStreamReader.ReadAsync(buff, 0, buff.Length);

                    if (readByteCount <= 0)
                    {
                        Debug.WriteLine("Disconnected from server.");
                        mClient.Close();
                        break;
                    }

                    Debug.WriteLine(
                        string.Format("Received bytes: {0} - Message: {1}",
                        readByteCount, new string(buff)));

                    Array.Clear(buff, 0, buff.Length);
                }
            }
            catch (Exception excp)
            {
                Console.WriteLine(excp.ToString());
                throw;
            }
        }
    }


}

ReadDataAsync() 可以在输出中显示消息,但我想在 Form1 中显示消息。所以我把 label1 放在 Form 中。我像这样单击 button1 时连接到服务器。

namespace TestClient
{
    public partial class Form1 : Form
    {

        SocketClient client = new SocketClient();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {


            if(!client.SetServerIPAddress("127.0.0.1")||
            !client.SetPortNumber("23000"))
            {

                Debug.WriteLine("Wrong IP Address or port");
                return;
            }

            client.ConnectToServer();
            string strInputUser = null;
        }

我可以将 ReadDataAsync() 中的消息显示给 Form1 吗?怎么做?

使用事件。

创建您自己的 EventArgs 来传输消息:

public class MessageEventArgs : EventArgs
{
    public string Message { get; private set; }

    public MessageEventArgs(string message)
    {
        this.Message = message;
    }
}

在您的 SocketClient class 中声明事件:

namespace SocketAsync
{
    public class SocketClient
    {
        IPAddress mServerIPAddress;
        int mServerPort;
        TcpClient mClient;

        public event EventHandler<MessageEventArgs> Message;

        // your other code
    }
}

同样在您的 SocketClient class 中,使用(引发)ReadDataAsync() 中的事件:

private async Task ReadDataAsync(TcpClient mClient)
{
    try
    {
        StreamReader clientStreamReader = new StreamReader(mClient.GetStream());
        char[] buff = new char[64];
        int readByteCount = 0;

        while (true)
        {
            readByteCount = await clientStreamReader.ReadAsync(buff, 0, buff.Length);

            if (readByteCount <= 0)
            {
                Message?.Invoke(this, new MessageEventArgs("Disconnected from server."));
                Debug.WriteLine("Disconnected from server.");
                mClient.Close();
                break;
            }

            Message?.Invoke(this, new MessageEventArgs(string.Format("Received bytes: {0} - Message: {1}",
                readByteCount, new string(buff))));
            Debug.WriteLine(
                string.Format("Received bytes: {0} - Message: {1}",
                readByteCount, new string(buff)));

            Array.Clear(buff, 0, buff.Length);
        }
    }
    catch (Exception excp)
    {
        Console.WriteLine(excp.ToString());
        throw;
    }
}

最后,在您的表单中使用事件:

namespace TestClient
{
    public partial class Form1 : Form
    {

        SocketClient client = new SocketClient();

        public Form1()
        {
            InitializeComponent();

            client.Message += Client_Message;
        }

        private void Client_Message(object sender, MessageEventArgs e)
        {
            label1.Invoke(new Action() => label1.Text = e.Message);
        }

        // your other code
    }
}