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