关于C#异步方法调用

 

        当我们在程序上要做的某个操作效为耗时(比如连接到网络验证登录信息)时,采用导步方法调用,可以在主线程上继续处理其它操作。比如在一个WinForm应用程序当中,我们做一个登录程序。如果采用常规的方式去进行登录验证这可能会有很长一段时间的网络缓时。在没有返回登录验证结果之前,如果不做一些视角上的处理。程序会显得很死板。这时候异步方法调用就显得很有用。(注意:我这里只是以登录为例,并不是说异步方法调用只能用在这方面)


       要执行异步调用,首先需要一个委托来挂起执行异步调用。这个委托你可以随心而定。但是它将要指向一个你将要作为用于异步调用的方法。有定义好了委托,接下来编写一个你要用于异步调用执行的方法(这里就叫它“异步方法”),它必须与你定义的委托一致。然后,还需要一个异步回调方法。
       异步回调方法在异步调用完成后会自动执行。比如,你的异步方法是用于连接到网络进行身份验证并返回验证结果。那么它返回这个结果就需要在异步回调方法当中去取得。异步回调方法还必须要一个IAsyncResult接口作为参数。IAsyncResult 接口由包含可异步操作的方法的类实现。它是启动异步操作的方法的返回类型。


      需要注意的是:异步调用将会创建一个子线程,所以,不能直接访问在主线程中创建的控件。解决这一问题C#提供了一个MethodInvoker委托,该委托可以执行托管代码中声明为void类型,并且不接受任何参数的方法。我们可以将控件的操作编写成这样的一个方法在子线程用MethodInvoker委托指向它即可。

下例代码为一个采用异步调用的登录程序,此代码只在此作为例子,没有完整的程序无法执行。本代码是我在实际项目中的应用严禁转载!!!

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace SysUI
{
    public partial class UserLogin : Form
    {
        public bool IsLogin;
        private string useName = string.Empty;
        private string usePassword = string.Empty;

        public UserLogin()
        {
            InitializeComponent();
        }

        private int loginstate = -1;
        /// <summary>
        /// 创建异步调用委托
        /// </summary>
        /// <returns></returns>
        private delegate int AsyncMethodCaller();

        /// <summary>
        /// 取消登录
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            IsLogin = false;
            this.Close();
        }

        /// <summary>
        /// 验证并返回登录状态[异步方法]
        /// </summary>
        /// <returns></returns>
        private int ToLogin()
        {
            try
            {
                DignityVerifiesServer.DignityVerifiesServer LogInObj = new SysUI.DignityVerifiesServer.DignityVerifiesServer();
                int loginstate = LogInObj.DignityVerifies(this.useName, this.usePassword);
                LogInObj.Dispose();
                return loginstate;
            }
            catch
            {
                return 403;
            }
        }

        /// <summary>
        /// 异步回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void Callback(IAsyncResult ar)
        {
            AsyncMethodCaller caller = (AsyncMethodCaller)ar.AsyncState;
            loginstate = (int)caller.EndInvoke(ar);
            MethodInvoker UnLoading = new MethodInvoker(this.Unlogin);
            UserService.UserService UseId = new SysUI.UserService.UserService();
            int userId = -1;
            Service.Service WriteLog = new SysUI.Service.Service();
            switch (loginstate)
            {
                case 404:
                    MessageBox.Show("登录失败:/r/r返回状态码:" + loginstate.ToString() + "/r/r错误描述:指定的用户不存在!", "登录失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
                case 403:
                    MessageBox.Show("登录失败:/r/r返回状态码:" + loginstate.ToString() + "/r/r错误描述:无法连接到服务器!", "登录失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
                case 400:
                    userId = UseId.getSelectedUserId(this.useName);
                    WriteLog.WriteLog("登录失败:原因,此用户已在使用中。", userId);
                    MessageBox.Show("用户不可用:/r/r返回状态码:" + loginstate.ToString() + "/r/r错误描述:指定的用户已经登录,无法继续使用此用户!", "登录失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
                case 500:
                    userId = UseId.getSelectedUserId(this.useName);
                    WriteLog.WriteLog("登录失败:原因,密码错误。", userId);
                    MessageBox.Show("登录失败:/r/r返回状态码:" + loginstate.ToString() + "/r/r错误描述:密码错误!", "登录失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
                case 100:
                    userId = UseId.getSelectedUserId(this.useName);
                    UseId.ReplacementOnLineState(userId, 1);
                    IsLogin = true;
                    WriteLog.WriteLog("登录成功。", userId);
                    break;
                default:
                    MessageBox.Show("登录失败:/r/r返回非遇期的状态码:" + loginstate.ToString() + "/r/r错误描述:内部应用程序异常!", "应用程序错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
            }
            UseId.Dispose();
            WriteLog.Dispose();
            this.Invoke(UnLoading);
        }

        /// <summary>
        /// 登录事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            this.StartLogIn();
        }

        /// <summary>
        /// 执行登录
        /// </summary>
        private void StartLogIn()
        {
            if (textBox1.Text == null || textBox1.Text.Trim() == "")
            {
                MessageBox.Show("请输入用户名!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                this.Unlogin();
                textBox1.Focus();
                return;
            }
            if (textBox2.Text == null || textBox2.Text.Trim() == "")
            {
                MessageBox.Show("请输入登录密码!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                this.Unlogin();
                textBox2.Focus();
                return;
            }
            this.useName = textBox1.Text.Trim();
            this.usePassword = textBox2.Text.Trim();
            this.logining();
            /******************创建异步委托实例*****************/
            AsyncMethodCaller caller = new AsyncMethodCaller(this.ToLogin);
            IAsyncResult result = caller.BeginInvoke(new AsyncCallback(this.Callback), caller);
            //IAsyncResult result = caller.BeginInvoke(textBox1.Text.Trim(), textBox2.Text.Trim(), null, null);
            this.logining();
        }
        /// <summary>
        /// 启动登录提示
        /// </summary>
        private void logining()
        {
            label1.Visible = false;
            label2.Visible = false;
            textBox1.Visible = false;
            textBox2.Visible = false;
            button1.Visible = false;
            button2.Visible = false;
            btnConfig.Visible = false;
            label3.Visible = true;
            LoadingImg.Visible = true;
        }

        /// <summary>
        /// 关闭登录提示
        /// </summary>
        private void Unlogin()
        {
            label3.Visible = false;
            LoadingImg.Visible = false;
            label1.Visible = true;
            label2.Visible = true;
            textBox1.Visible = true;
            textBox2.Visible = true;
            button1.Visible = true;
            button2.Visible = true;
            btnConfig.Visible = true;
            if (loginstate == 100)
                this.Close();
        }

        private void button1_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 13)
            {
                e.Handled = true;
                this.StartLogIn();
            }
        }

        private void UserLogin_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 13)
            {
                e.Handled = true;
                SendKeys.Send("{TAB}");
            }
        }

        /// <summary>
        /// 配置按钮触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConfig_Click(object sender, EventArgs e)
        {
            ConfigEdit frm = new ConfigEdit();
            frm.ShowDialog();
        }
    }
}

程序运行状况如下图:

                                   (图1:登录前)


                              (图2:验证进行中)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章