C#桌面应用使用异步计算改善界面效果的两种方式

在桌面应用中,我们希望当一个费时的运算在进行的时候,当前窗体可以有所表现,比如显示等待动画或者进度条,避免让用户陷入无聊、乏味又不知何时才能执行完成的苦闷之中,此时异步计算即可派上用场,所谓异步,即是将费时的运算放到一个专门的工作线程里面去,不在当前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;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值