在Winform开发中,客户体验是个很好的参考性指标,如果一个功能使用的时候感觉很流畅,说明我们的程序执行效率还不错,但是随着数据的真多,原先可能流程的地方可能会变得比较卡,这时候就需要追本索源,找到症结并进行处理。但是,如果我们对Winform开发有一定的经验积累,有些耗时缓慢的界面处理一开始还是比较容易避免,本文介绍一些在开发过程中的一些界面性能上的优化处理,希望对大家有帮助。
1、案例说明
在我开发的CRM系统中,系统的一些用户如经办人员,来自权限管理系统,因此在开发的时候,并没有模拟太多的用户,因此,开始的设计处理是通过下拉列表列出相关的用户即可,如下所示。
最开始的考虑是让用户能够快速选择所需要的经办人员,默认是当前用户,这种设计开始不会有任何问题,因为数据少,测试起来非常流畅。
插入用户的界面部分是这样处理的,由于这个经办人是很多界面地方用到的,所以把它封装为一个界面控件,需要的地方拖过去使用即可,和普通的文本框一样的使用方法。
上面的控件初始化的时候,应该列出一些用户信息,如下所示。
List<UserInfo> userList = BLLFactory<User>.Instance.GetAll(); foreach (SimpleUserInfo info in userList) { this.txtOperator.Properties.Items.Add(new CListItem(info.FullName, info.ID.ToString())); }
2、界面效率优化
1)优化一
上面的代码粗看没有什么问题,但是我们知道,下拉列表为了提高效率,一般有一个BeginUpdate,EndUpdate的方法用来实现批量录入。为了提高速度,这点我们需要利用上,然后代码就修改为下面的处理方式。
this.txtOperator.Properties.BeginUpdate(); List<UserInfo> userList = BLLFactory<User>.Instance.GetAll(); foreach (SimpleUserInfo info in userList) { this.txtOperator.Properties.Items.Add(new CListItem(info.FullName, info.ID.ToString())); } this.txtOperator.Properties.EndUpdate();
在数据不算很多的时候,感觉速度比原来却是快了一些。
2)优化二
但是发现我的权限系统用户数据增加到几百个的人员的时候,速度就有点卡了。问题出现在哪里?
由于权限管理系统中用户表是一个较为庞大的表,如下所示。
每次获取用户的时候,我们调用了下面的代码。
BLLFactory<User>.Instance.GetAll()
这个操作是把用户的全部信息字段都获取一次,速度肯定比较慢了,那么我们来改进一下,因为我们这里控件只需要绑定一些简单的用户名,用户ID,用户姓名等基础字段,我们来简化一个对象用来实现数据的获取,如下所示。
于是我在权限管理系统定义了一个简单的用户对象,称为SimpleUserInfo,它只是包含了几个基本的字段即可,这样绑定代码修改如下。
this.txtOperator.Properties.BeginUpdate(); this.txtOperator.Properties.Items.Clear(); List<SimpleUserInfo> userList = BLLFactory<User>.Instance.GetSimpleUsers(); foreach (SimpleUserInfo info in userList) { this.txtOperator.Properties.Items.Add(new CListItem(info.FullName, info.ID.ToString())); } this.txtOperator.Properties.EndUpdate();
好了,速度很快了,一眨眼功夫,几百个用户都列出来了,非常高兴。
3)优化三
上面确实感觉速度飞快了,几百个用户瞬间加载,解决了速度的问题,但是带来了另外一个问题,几百个用户,我们通过列表选择用户是否太费眼力了呢,一个个找,没有查找过滤?好费劲!
好既然速度提上来了,我们改进一下用户体验的效果吧,好像记得DevExpress有一个查找的下拉列表叫做SearchLookupEdit,就用它了。
先另外定义一个基于SearchLookupEdit的界面控件,如下所示。
设置它里面列表需要显示的字段,如下所示。
绑定代码如下所示。
private void OperatorSelectControl_Load(object sender, EventArgs e) { if (!this.DesignMode) { txtOperator.Properties.ValueMember = "ID"; txtOperator.Properties.DisplayMember = "FullName"; txtOperator.Properties.DataSource = BLLFactory<User>.Instance.GetSimpleUsers(); } }
上面的设计和代码绑定弄完成后,我们来看看具体的效果了。
通过弹出的GridView里面展示用户信息,并能支持查询搜索,选择用户速度快了很多,同时也提高用户体验。
4)优化四
说完了优化三,看到优化四,是不是心里说道,不是吧,还有更好的?
当然,我们知道Winform里面很多时候,数据可能都会被反复使用,如经办人员,一般来说,很多界面可能都需要,那么每次都需要从数据库里面取出几百个用户,效率上感觉还是不太好,特别如果是在我的混合式框架中用到的WCF的分布式获取数据方式,也就是说数据不再本地,需要通过网络方式获取,那么就会产生带宽的问题,效率可能无法保证。
好了,说到这里,就是指我想把这些常用到,不会经常变化的数据缓存起来,供下一步继续使用。
我们看看获取用户数据的地方修改为下面的方法,关于MemoryCacheHelper的定义及说明,可以参考我上一篇介绍WInform里面使用缓存的随笔《Winform里面的缓存使用》。
/// <summary> /// 获取用户全部简单对象信息,并放到缓存里面 /// </summary> /// <returns></returns> public static List<SimpleUserInfo> GetSimpleUsers() { System.Reflection.MethodBase method = System.Reflection.MethodBase.GetCurrentMethod(); string key = string.Format("{0}-{1}", method.DeclaringType.FullName, method.Name); return MemoryCacheHelper.GetCacheItem<List<SimpleUserInfo>>(key, delegate() { return BLLFactory<User>.Instance.GetSimpleUsers(); }, new TimeSpan(0, 10, 0));//10分钟过期 }
好了,使用缓存获取数据,我们只需要稍微调整下控件的获取数据代码即可,如下所示。
private void OperatorSelectControl_Load(object sender, EventArgs e) { if (!this.DesignMode) { txtOperator.Properties.ValueMember = "ID"; txtOperator.Properties.DisplayMember = "FullName"; txtOperator.Properties.DataSource = SecurityHelper.GetSimpleUsers(); } }
以上经验就是在我的《CRM客户关系管理系统》里面,对于经办人这样的用户选择界面所做的一步步精益求精的优化尝试和历程,希望给大家在做同样操作的时候常考。
如果有兴趣,可以进一步了解这个系统的各种界面设计效果。