利用IExtendProvider簡(jiǎn)化Entity和UI數(shù)據(jù)交換
大家知道UpdateData就是將從UI的各個(gè)控件的屬性中讀取數(shù)據(jù),在賦值到實(shí)體的屬性中;UpdateUI就是反過(guò)來(lái),從實(shí)體的屬性中讀取數(shù)據(jù),再賦值給UI的各個(gè)控件的屬性。
先舉個(gè)例子:
- 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;
- }
如果實(shí)體的屬性數(shù)據(jù)比較少,這么寫(xiě)沒(méi)什么問(wèn)題。但是復(fù)雜的實(shí)體動(dòng)則10幾個(gè)屬性,寫(xiě)起來(lái)看了都怕。因此,有了一個(gè)叫做代碼生成器的東西,可以自動(dòng)生成UI的代碼,省掉了一些體力勞動(dòng)。但是,我們不是僅僅寫(xiě)了一次就ok,有時(shí)還要修改。不小心改了一個(gè)名字忘了點(diǎn)重構(gòu)就直接吐血而亡。況且,那么一大堆的代碼在那里也不是一成不變,有時(shí)候改了類型還得加上強(qiáng)制轉(zhuǎn)換。有時(shí)為了方便,我們還會(huì)建立一個(gè)字典,將UI控件和實(shí)體的屬性對(duì)應(yīng)起來(lái)。
本人也屬于懶人,之前也搞過(guò)用字典映射,但始終覺(jué)得不夠人性化,就總琢磨著怎么給這個(gè)方法來(lái)個(gè)升華。畢竟UI都是這個(gè)東西再怎么生成,多少還是要用到IDE的可視化功能吧,如果能向設(shè)置屬性那樣,設(shè)置哪個(gè)屬性對(duì)應(yīng)哪個(gè)控件是否會(huì)好些?
不要太復(fù)雜,直接輸入實(shí)體屬性的名稱、控件屬性的名稱、是否允許空值、是否只讀對(duì)于數(shù)據(jù)交換來(lái)說(shuō)就夠了吧。要實(shí)現(xiàn)這個(gè)必然要擴(kuò)展原來(lái)那些標(biāo)準(zhǔn)控件,向devExpress那樣的第三方控件學(xué)習(xí),似乎沒(méi)那么干勁自己寫(xiě)。于是就以ToolTip為榜樣,用IExtenderProvider來(lái)實(shí)現(xiàn)所需的功能。
首先定義一個(gè)MappingInfo來(lái)存儲(chǔ)上面說(shuō)到的信息。再來(lái)就是定義一個(gè)對(duì)象(我的叫UIMapper),實(shí)現(xiàn)IExtenderProvider(這一步?jīng)]什么好說(shuō)的了,關(guān)鍵是ProvidePropertyAttribute別設(shè)置錯(cuò)誤,否則啥都擴(kuò)展不出來(lái))。提供2個(gè)方法,UpdateData和UpdateUI并針對(duì)DataRow和object的重載。然后就大功告成。在需要數(shù)據(jù)交換的地方之需要簡(jiǎn)單調(diào)用UpdateData和UpdateUI即可。比如上面的那小段代碼就可以改為UIMapper1.UpdateData(ticketSaleBill)或這UIMapper1.UpdateUI(ticketSaleBill)。
IExtendProvider使用總結(jié):
<!--[if !supportLists]-->1、對(duì)于屬性的賦值。有時(shí)候我們可能需要要對(duì)UI控件更深一個(gè)層次的屬性賦值或取值,比如devExpress那些Edit常用的XXEdit1.Propertys.XXValue為了實(shí)現(xiàn)這個(gè)功能只好首先自己動(dòng)手,按“.”分割字符串,然后利用反射逐級(jí)獲取對(duì)象的實(shí)例。而且在嵌套發(fā)生時(shí),并不能確定是Property還是Field,為了應(yīng)對(duì)不同的情況BindingFlag最好設(shè)為BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.GetField,然后利用InvokeMember來(lái)執(zhí)行操作。
<!--[if !supportLists]-->2、利用反射+Converter能實(shí)現(xiàn)大部分類型的轉(zhuǎn)換,但不能針對(duì)所有的類型。目前的做法是增加QueryObjectValue的事件,用于在賦值時(shí)由用戶處理特殊的類型轉(zhuǎn)換。
<!--[if !supportLists]-->3、在賦值發(fā)生異常時(shí)同樣通過(guò)事件通知用戶,由用戶決定處理的方式。在UpdateUI或UpdateData調(diào)用結(jié)束之后,返回Dictionary<object, Exception>即控件和異常的字典。
<!--[if !supportLists]-->4、用IExtenderProvider實(shí)質(zhì)上也是用Dictionary來(lái)實(shí)現(xiàn)擴(kuò)展,但其在設(shè)計(jì)時(shí)可以直觀進(jìn)行編輯,在運(yùn)行時(shí)也可以簡(jiǎn)單方便地進(jìn)行擴(kuò)展。
<!--[if !supportLists]-->5、 雖然反射的速度要比直接賦值慢,但是在這種情況下還是可取的。特別是當(dāng)實(shí)體的屬性較多或者數(shù)據(jù)庫(kù)表字段較多的情況下,可以在設(shè)計(jì)時(shí)直接設(shè)置,減少了代碼量。
【編輯推薦】