大家知道UpdateData就是将从UI的各个控件的属性中读取数据,在赋值到实体的属性中;UpdateUI就是反过来,从实体的属性中读取数据,再赋值给UI的各个控件的属性。
先举个例子:
- public void UpdateUI(TTicketSaleBill ticketSaleBill)
- {
- ....
- edit_CreatorId.StringValue = ticketSaleBill.CreatorId;
- edit_CreateDateTime .DateTime = ticketSaleBill.CreateDateTime ;
- edit_ModifierId.StringValue = ticketSaleBill.ModifierId ;
- edit_ModifyDateTime .DateTime = ticketSaleBill.ModifyDateTime ;
- }
- public void UpdateData(TTicketSaleBill ticketSaleBill)
- {
- ....
- if(ticketSaleBill.PersistState == Fx.Common.Data.TPersistState.Added)
- {
- ticketSaleBill.CreatorId = this.Context.SecurityCtx.LoginUser.Id ;
- ticketSaleBill.CreateDateTime = DateTime.Now;
- }
- ticketSaleBill.ModifierId = this.Context.SecurityCtx.LoginUser.Id;
- ticketSaleBill.ModifyDateTime = DateTime.Now;
- }
如果实体的属性数据比较少,这么写没什么问题。但是复杂的实体动则10几个属性,写起来看了都怕。因此,有了一个叫做代码生成器的东西,可以自动生成UI的代码,省掉了一些体力劳动。但是,我们不是仅仅写了一次就ok,有时还要修改。不小心改了一个名字忘了点重构就直接吐血而亡。况且,那么一大堆的代码在那里也不是一成不变,有时候改了类型还得加上强制转换。有时为了方便,我们还会建立一个字典,将UI控件和实体的属性对应起来。
本人也属于懒人,之前也搞过用字典映射,但始终觉得不够人性化,就总琢磨着怎么给这个方法来个升华。毕竟UI都是这个东西再怎么生成,多少还是要用到IDE的可视化功能吧,如果能向设置属性那样,设置哪个属性对应哪个控件是否会好些?
不要太复杂,直接输入实体属性的名称、控件属性的名称、是否允许空值、是否只读对于数据交换来说就够了吧。要实现这个必然要扩展原来那些标准控件,向devExpress那样的第三方控件学习,似乎没那么干劲自己写。于是就以ToolTip为榜样,用IExtenderProvider来实现所需的功能。
首先定义一个MappingInfo来存储上面说到的信息。再来就是定义一个对象(我的叫UIMapper),实现IExtenderProvider(这一步没什么好说的了,关键是ProvidePropertyAttribute别设置错误,否则啥都扩展不出来)。提供2个方法,UpdateData和UpdateUI并针对DataRow和object的重载。然后就大功告成。在需要数据交换的地方之需要简单调用UpdateData和UpdateUI即可。比如上面的那小段代码就可以改为UIMapper1.UpdateData(ticketSaleBill)或这UIMapper1.UpdateUI(ticketSaleBill)。
IExtendProvider使用总结:
<!--[if !supportLists]-->1、对于属性的赋值。有时候我们可能需要要对UI控件更深一个层次的属性赋值或取值,比如devExpress那些Edit常用的XXEdit1.Propertys.XXValue为了实现这个功能只好首先自己动手,按“.”分割字符串,然后利用反射逐级获取对象的实例。而且在嵌套发生时,并不能确定是Property还是Field,为了应对不同的情况BindingFlag最好设为BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.GetField,然后利用InvokeMember来执行操作。
<!--[if !supportLists]-->2、利用反射+Converter能实现大部分类型的转换,但不能针对所有的类型。目前的做法是增加QueryObjectValue的事件,用于在赋值时由用户处理特殊的类型转换。
<!--[if !supportLists]-->3、在赋值发生异常时同样通过事件通知用户,由用户决定处理的方式。在UpdateUI或UpdateData调用结束之后,返回Dictionary<object, Exception>即控件和异常的字典。
<!--[if !supportLists]-->4、用IExtenderProvider实质上也是用Dictionary来实现扩展,但其在设计时可以直观进行编辑,在运行时也可以简单方便地进行扩展。
<!--[if !supportLists]-->5、 虽然反射的速度要比直接赋值慢,但是在这种情况下还是可取的。特别是当实体的属性较多或者数据库表字段较多的情况下,可以在设计时直接设置,减少了代码量。
【编辑推荐】