C#桌面应用使用异步计算改善界面效果的两种方式
2007-12-20 13:47
861 查看
在桌面应用中,我们希望当一个费时的运算在进行的时候,当前窗体可以有所表现,比如显示等待动画或者进度条,避免让用户陷入无聊、乏味又不知何时才能执行完成的苦闷之中,此时异步计算即可派上用场,所谓异步,即是将费时的运算放到一个专门的工作线程里面去,不在当前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;
好了,说了使用和不用异步运算的区别,我们下边说说在.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;
相关文章推荐
- C#桌面应用使用异步计算改善界面效果的两种方式
- Android应用界面无标题栏和全屏效果的两种实现方式
- C#之使用NotifyIcon实现任务栏托盘菜单,图标闪烁效果及气泡提示 很多程序是只需要后台运行的,甚至不需要自己的应用界面。NotifyIcon提供了程序在任务栏的显示功能 程序下载链接如下
- C#替换桌面的两种方式
- c# 字符串连接使用“+”和string.format格式化两种方式
- 在C#代码中应用Log4Net(二)典型的使用方式
- 使用PopupWindow和Activity两种不同的方式实现弹窗效果
- 利用JavaFx开发RIA桌面应用-加载等待界面禁用的两种不同方法
- C# 系统应用之透明罩MyOpaqueLayer实现360界面阴影效果
- C#环境下利用VS2017使用MapXtreme7.0.0开发桌面应用实例
- Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比
- Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比--转载
- Android - 代码的组织方式,splash界面,获取应用的版本号,获取服务器版本号,下载安装apk,跑马灯效果
- 在C#代码中应用Log4Net(二)典型的使用方式
- 在C#代码中应用Log4Net(二)典型的使用方式
- MyBatis之自查询使用递归实现 N级联动效果(两种实现方式)
- 使用PopupWindow和Activity两种不同的方式实现弹窗效果
- 使用C#编写可被桌面应用调用的ActiveX控件
- Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比
- 两种方法使用jquery实现左右移动效果(包含each遍历方式)