1
概述
Introduction to new functions
今天借GIS项目实现一个进度条效果,这个效果在各种管理系统中是最常见的一个效果,特别是在处理某个任务消耗的时间过长的场景,可以避免UI假死,提高用户体验。我这次用的POI数据大概有90W条,这个目录树是我为了练手,故意拆成五层的,其实从第三层到第五层原本是放在一个字段里的string型POI类型描述,将它拆解成三层树结构时损耗了部分性能,到最下面一层(图标是感叹号)类型,大概有5700多个叶子节点,加载这个资源目录树需要一段时间,这里用委托实现页面传值 BackgroundWorker实现异步弹框进度条效果。我原来在winform里面实现过,但是WPF框架里还没做过,拿这个练练手,为今后的工(qiu)作(zhi)任(mian)务(shi)做好技术储备。
委托是一种引用类型,它是函数指针的托管版本。
2
功能实现
Function
废话不多说直接上图。示例只用了一个区的数据,读取全市数据太慢了。
http://mpvideo.qpic.cn/0bc3b4an2aaakmam7zdkbnrvad6d3uhqbxia.f10002.mp4?dis_k=e7829d8870a9a1e26d46f36d5369b94f&dis_t=1669881228&vid=wxv_2655894180405231616&format_id=10002&support_redirect=0&mmversion=false
3
核心功能代码
Code
委托页面传值是委托的一个最简单应用场景,大家可以拿来练练手,边做边理解一下委托的概念,我把委托传值用法的大致思路画了一个草稿,见下图,希望对大家理解有帮助。代码最后那个“百分比处理”的代码是我在网上copy的一个觉得比较别致的写法,纯属收藏,实际处理百分比不需要那么啰嗦,求x的时候不乘以100,直接加上百分符号就完事了。
弹框代码示例
代码语言:javascript复制// 文本框赋值方法 的委托属性
private LoadDataEventHandler _loadDataSubWindowDel;
BackgroundWorker worker = null;
/// <summary>
///
/// </summary>
/// <param name="typeString"></param>
/// <param name="adname"></param>
/// <param name="del"></param>
public WindowForDataLoadProcess(string typeString, string adname, LoadDataEventHandler del)
{
InitializeComponent();
worker = new BackgroundWorker();
//异步取消 需要增加这个 不然取消失效
worker.WorkerSupportsCancellation = true;
//支持报告进度
worker.WorkerReportsProgress = true;
//注册滚动条事件
worker.ProgressChanged = ProgessChangedInit;
//注册任务
worker.DoWork = DoWorkInit;
//任务完毕触发
worker.RunWorkerCompleted = CompleteWorkInit;
StartKeyCompareRunning(typeString, adname); //这个是我的启动方法
this._loadDataSubWindowDel = del;
}
#region BackgroundWorker 多线程
/// <summary>
/// 第一次打开Form
/// </summary>
private void StartKeyCompareRunning(string typeString, string adname)
{
string[] para = { typeString, adname };
worker.RunWorkerAsync(para);
}
//调用 RunWorkerAsync 时发生
public void DoWorkInit(object sender, DoWorkEventArgs e)
{
if (worker.CancellationPending) //判断是否取消操作
{
e.Cancel = true; //这里才真正取消
return;
}
else
{
string[] receive = e.Argument as string[];
e.Result = LoadData(worker, e, receive); //LoadData就是读取数据并处理进度条report事件的自定义方法
}
}
//调用 ReportProgress 时发生
public void ProgessChangedInit(object sender, ProgressChangedEventArgs e)
{
//将异步任务进度的百分比赋给进度条
this.progressBar1.Value = e.ProgressPercentage;
this.Label1.Content = (string)e.UserState;
}
/// <summary>
/// 当后台操作已完成、被取消或引发异常时发生
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void CompleteWorkInit(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
System.Windows.MessageBox.Show("Progess is interrupted!");
}
else if (e.Error != null)
{
System.Windows.MessageBox.Show("Worker exception: " e.Error.ToString());
}
else
{
try
{
FormMainProgressBarResult re = (FormMainProgressBarResult)e.Result;
this.Close();
//委托返回值给父窗口
_loadDataSubWindowDel(re); //委托传值回主界面
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
#region load数据
/// <summary>
/// 组装树的数据集
/// </summary>
private FormMainProgressBarResult LoadData(BackgroundWorker worker, DoWorkEventArgs e, string[] paraArray)
{
FormMainProgressBarResult iRel = new FormMainProgressBarResult();
try
{
组装DataTable dtLevel5 数据集(方法略),dtLevel5是第五层叶子节点
dtLevel5 装进dt里,dt是总数据集
foreach (DataRow d5 in dtLevel5.Rows)
{
DataRow dr5 = dt.NewRow();
dr5["id"] = d5["Name"];
.....
dt.Rows.Add(dr5);
}
//进度条计算
index = index dtLevel5.Rows.Count;
int x = (int)Math.Floor((double)((index 1) * 100 / AllRows));
//百分比处理
System.Globalization.NumberFormatInfo provider = new System.Globalization.NumberFormatInfo();
provider.PercentDecimalDigits = 0;//小数点保留几位数.
provider.PercentPositivePattern = 0;//百分号出现在何处.
double result = (double)x/100;//一定要用double类型.
report_message = result.ToString("P", provider);
worker.ReportProgress(x, report_message);
组装dt完毕后放进返回值
iRel.ResultDataTable = dt;
iRel.ResultString = "ok";
iMsgRel = 1;
return iRel;
}
catch (Exception ex)
{
iRel.ResultDataTable = null;
iRel.ResultString = ex.Message;
return iRel;
}
}
#endregion