C# : 异步更新UI

源于

提示:该程序为C#的Winform程序,可在Windows上直接运行.

之前写了一个Winform程序,需要异步更新UI(例如,在Android中,是明确禁止同步更新UI的.).于是请教了一些网友,得出下面的程序.

其实原理都比较简单,就是把网络请求放到另外一个线程里面去执行.等网络请求线程执行完成之后,通过回调或其他方式执行UI线程更新.

image-2857

运行截图

程序运行截图如下,图示为已经加载完成数据的效果:

image-2858

源码

完整源码在: Gitee仓库

请求的网络地址为: http://www.weather.com.cn/data/sk/101270101.html,有时候网络会比较慢..

发送请求封装部分:

// allDone 属性包含 ManualResetEvent 类的实例,它指示请求完成。
        public ManualResetEvent allDone = new ManualResetEvent(false);

        // 它创建 WebRequest wreq 和 RequestState rs,调用 BeginGetResponse 开始处理请求,然后调用 allDone.WaitOne() 方法,
        // 以便应用程序不会在回调完成前退出。 在从 Internet 资源读取响应后,Main() 将该响应写入到控制台,应用程序结束。
        public void SendGet(string url,  HttpResultGet resultGet, FormInterface formTransInterface, WebHeaderCollection whcl = null)
        {
            try
            {
                WebRequest wreq = WebRequest.Create(url);
                if (whcl != null)
                {
                    ((HttpWebRequest)wreq).Headers = whcl;
                }
                // Create the state object.  
                ASyncRequestState rs = new ASyncRequestState
                {
                    // Put the request into the state object so it can be passed around.  
                    Request = wreq
                };

                // Issue the async request.  
                IAsyncResult r = wreq.BeginGetResponse(
                   new AsyncCallback(RespCallback), rs);

                // Wait until the ManualResetEvent is set so that the application   
                // does not exit until after the callback is called.  
                allDone.WaitOne();
                if (rs.RequestData.ToString().Length > 0)
                {
                    resultGet.ResultSet(rs.RequestData.ToString(), formTransInterface);
                }
            }
            catch (WebException)
            {
                resultGet.ResultSet("[请求错误]网络请求发生未知错误,请稍候重试!", formTransInterface);
            }
            catch (Exception)
            {
                resultGet.ResultSet("[请求错误]网络请求发生未知错误,请稍候重试!", formTransInterface);
            }

        }

异步回调封装部分:

// RespCallBack() 方法实现 Internet 请求的异步回调方法。 
        // 该方法创建包含来自 Internet 资源的响应的 WebResponse 实例,
        // 获取响应流,然后开始从该流异步读取数据。
        private void RespCallback(IAsyncResult ar)
        {
            // Get the ASyncRequestState object from the async result.  
            ASyncRequestState rs = (ASyncRequestState)ar.AsyncState;

            // Get the WebRequest from AsyncRequestState.  
            WebRequest req = rs.Request;

            // Call EndGetResponse, which produces the WebResponse object  
            //  that came from the request issued above.  
            WebResponse resp = req.EndGetResponse(ar);

            //  Start reading data from the response stream.  
            Stream ResponseStream = resp.GetResponseStream();

            // Store the response stream in AsyncRequestState to read   
            // the stream asynchronously.  
            rs.ResponseStream = ResponseStream;

            // Open the stream using a StreamReader for easy access.  
            StreamReader reader = new StreamReader(ResponseStream);
            // Read the content.  
            string responseFromServer = reader.ReadToEnd();

            rs.RequestData.Append(
                   responseFromServer);

            // Close down the response stream.  
            reader.Close();
            // Set the ManualResetEvent so the main thread can exit.  
            allDone.Set();
        }

代码调用:

        /**
         * 发送异步网络请求.
         *
         *
         */
        public void SendGet(string url, FormInterface formInterface)
        {

            // 随便显示的一个天气地址.
            AsyncHttpUtil asyncHttpUtil = new AsyncHttpUtil();
            asyncHttpUtil.SendGet(url, new SendHTTP(), formInterface);
        }

        // 异步回调
        void HttpResultGet.ResultSet(string result, FormInterface formInterface)
        {
            formInterface.SendResult(result);
        }

程序入口调用:

/**
         * 接收异步返回结果.
         * 
         */
        void FormInterface.SendResult(string text)
        {
            MessageBox.Show(text);
            this.targetText.Text = text;
        }
        /**
         * 模拟发送异步请求.
         *    
         */
        private void send_Click(object sender, EventArgs e)
        {
            SendHTTP send = new SendHTTP();
            send.SendGet("http://www.weather.com.cn/data/sk/101270101.html", this);
        }

完整源码在: Gitee仓库