當我們在程序上要做的某個操作效爲耗時(比如連接到網絡驗證登錄信息)時,採用導步方法調用,可以在主線程上繼續處理其它操作。比如在一個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();
}
}
}