程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> C#桌面應用使用異步計算改善界面效果的兩種方式

C#桌面應用使用異步計算改善界面效果的兩種方式

編輯:.NET實例教程

在桌面應用中,我們希望當一個費時的運算在進行的時候,當前窗體可以有所表現,比如顯示等待動畫或者進度條,避免讓用戶陷入無聊、乏味又不知何時才能執行完成的苦悶之中,此時異步計算即可派上用場,所謂異步,即是將費時的運算放到一個專門的工作線程裡面去,不在當前UI線程裡面處理,如果在UI線程內處理,UI勢必會進入假死狀態,期間用戶無法移動窗體,無法取消費時操作,只能等待程序處理完畢,程序的控制權才會重新交換給用戶,這種方式前面也說了,相當的不友好!其實這裡的異步操作類似於web開發中常用的AJax,調用XMLHTTP在後台操作,等操作完成後調用回調函數,給用戶結果,控制權一直都在用戶手裡,感覺肯定不一樣。:)

好了,說了使用和不用異步運算的區別,我們下邊說說在.Net中,使用C#語言,實現異步操作的兩種方式:

一,使用delegate代理

1、假如需要在工作線程進行長時間工作的方法是:int StartExportData()



//導出舊庫
public int StartExportData()
{
    return new ExportData().StartExportDataToTmp();
}

2、定義上述方法的委托方法



//StartExportData方法委托,異步調用StartExportData方法,避免主線程阻塞。
delegate int StartExportDataDelegate();

3、定義回調方法,指示當StartExportData()執行完成後所進行的操作



//回調方法,當StartExportData方法執行完畢返回後執行的回調。
public void ExportCallBackMethod(System.IAsyncResult exportResult)
{
    //獲得委托對象
    StartExportDataDelegate d1 = (StartExportDataDelegate)exportResult.AsyncState;
    //EndInvoke方法必須調用,取得被委托方法的返回值
    int result = d1.EndInvoke(exportResult);
    if (result == 1)    //如果返回為1,表示外部程序成功返回
    {
        ShowMessage("成功導出舊年度數據庫 ...");    //更新信息提示

    }
    d1 = null;
}

4、在新的工作線程內啟動被代理的方法



//初始化委托方法對象
StartExportDataDelegate d1 = new StartExportDataDelegate(StartExportData);
//初始化回調方法對象
System.AsyncCallback c1 = new System.AsyncCallback(ExportCallBackMethod);
//使用BeginInvoke方法啟動異步線程,在線程內執行被委托方法StartExportData,
//線程執行完畢後調用回調方法CallBackMethod
d1.BeginInvoke(c1, d1);

5、最後,要說明的是,需要引入Threading:



using System.Threading;

二、使用BackgroundWorker 類,它是在 .Net Framework 2.0 版中是新增的。

還是對上述方法的異步調用,換用BackgroundWorker後會是怎樣的呢?我們一起來看一下:

1、初始化類的兩個事件:DoWork和RunWorkerCompleted,顧名思義,DoWork即為工作線程,在該方法內調用工作方法; RunWorkerCompleted即為回調方法,即為工作方法完成後所調用的方法。這裡的bgWorker為BackgroundWorker類的實例。



/// <summary>
/// 初始化工作線程事件處理程序
/// </summary>
private void initBackgroundWorker()
{
    bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
    bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
}

2、在類的構造函數內調用上述初始化方法。



public BaseDataForm()
{
    InitializeComponent();
    initBackgroundWorker();
}

3、修改方法的簽名,增加兩個參數。



private int StartExportData(BackgroundWorker worker, DoWorkEventArgs e)
{
    try
    {
        ... ...
    }
    finally
    {

    }
    return 0;
}

4、實現DoWork方法。



/// <summary>
/// 工作線程所做工作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    e.Result = process(worker, e);
    //以下為接受多個參數的方法,一個參數就不用說了吧 :)
    //string arg1 = ((ArrayList)e.Argument)[0].ToString();
    //string arg2 = ((ArrayList)e.Argument)[1].ToString();
    //e.Result = compare(arg1, arg2 , worker, e);
}

 

5、實現RunWorkerCompleted方法。



/// <summary>
/// 工作線程結束後所做工作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
    {
        ShowMessage(ResUtils.getString(("TaskError")));
        btnStart.Enabled = true;
        btnClose.Enabled = true;
        picBox.Enabled = false;
        MessageBox.Show(e.Error.Message, SystemContext.APP_TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error);
        if (log.IsErrorEnabled)
        {
            log.Error(e.Error.Message, e.Error);
        }
    }
    else
    {
        ShowMessage(ResUtils.getString(("TaskSuccess")));
   btnStart.Enabled = true;
        btnClose.Enabled = true;
        picBox.Enabled = false;
    }
}

6、啟動後台工作線程。



private void btnStart_Click(object sender, EventArgs e)
{
    if (check())
    {
        btnStart.Enabled = false;
        btnClose.Enabled = false;
        bgWorker.RunWorkerAsync();//這裡可以添加一個參數對象,如果單個參數直接傳,如果多個參數封裝到類或ArrayList

    //以下為傳送多個參數的方法,一個參數就不用說了吧 :)
    //ArrayList arg = new ArrayList(2);
    //arg.Add(txtExcelFile.Text);
    //arg.Add(cmbReportType.Text);
    //bgWorker.RunWorkerAsync(arg); //暈啊,傳多個參數竟然非要用數組或者對象
    }
}

7、最後,同樣,要引入的類為:



using System.Threading;
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved