前言 隨著 DEV24.1.3 的發佈,XAF Blazor 中的屬性編輯器(PropertyEditor)也進行了很大的改動,在使用體驗上也更接近 WinForm 了,由於進行了大量的封裝,理解上沒有 WinForm 直觀,所以本文通過對屬性編輯器的原理進行解析,並對比新舊版本中的變化,使大家能夠 ...
前言
隨著 DEV24.1.3 的發佈,XAF Blazor 中的屬性編輯器(PropertyEditor)也進行了很大的改動,在使用體驗上也更接近 WinForm 了,由於進行了大量的封裝,理解上沒有 WinForm 直觀,所以本文通過對屬性編輯器的原理進行解析,並對比新舊版本中的變化,使大家能夠對屬性編輯器有一個更全面的認識。
原理
XAF 可以創建與平臺無關的業務代碼,而 PropertyEditor 就是它們與各個平臺之間的一個橋梁,也就是說 PropertyEditor 每個平臺都有各自的實現。從錶面上看 PropertyEditor 的原理並不複雜,BO 中屬性的更改會觸發 PropertyEditor 中值的更改,而 PropertyEditor 值的更改又會更新具體平臺組件的值,反過來也是一樣,組件值的更改會觸發 PropertyEditor 值的更改,而PropertyEditor 值的更改又會更新 BO 中的屬性值。
如果我們使用的是XPO,PersistentBase 是全部 BO 的基類,它實施一個 INotifyPropertyChanged 介面,我們可以通過 INotifyPropertyChanged 介面來監聽每一個屬性的變化,這樣我們就可以在屬性值發生變化時通知 PropertyEditor,而這個監聽工作是在 DetailView 中完成的。DetailView 在監聽到 BO 中屬性值發生更改時,會查找到具體的 PropertyEditor,並調用它的 Refresh 方法。
PropertyEditor 的屬性(如:Caption,DisplayFormat)大部分來自 XAF 的 Model,也就是在 PropertyEditor 初始化時會傳遞一個 IModelMemberViewItem 對象,它裡面包含了我們在模型編輯器中設置的值或一些預設值。
PropertyEditor 中有兩個比較重要的方法 ReadValue 與 WriteValue,我一開始看到這個兩方法時也產生了混淆,ReadValue 與 WriteValue 它們針對的對象是 BO 中的屬性,而不是 PropertyEditor,也就是說 ReadValue 是讀取 BO 中屬性的值,而 WriteValue 是將值寫入到屬性中。
PropertyEditor 中還有一個 Control 屬性,它的類型是 Object,不同的平臺它返回的類型是不一樣的,這個也是各個平臺的組件,WinForm 返回的是 Control 類型,Blazor 返回的是 ComponentAdapter 或 ComponentModel (24.1.3之後 XAF 自帶編輯器預設返回類型)。由於不同的平臺渲染方式不同,對於 WinForm 來說,它返回的是 Control 類型,可以直接將其放置到父組件的 Controls 中,而對於 Blazor 就不行,Blazor 組件就不能像 WinForm 控制項那樣操作,它是通過 RenderFragment 進行組合在一起的,所以 Blazor 中的 PropertyEditor 同時還實施了一個 IComponentContentHolder 介面,通過它可以返回一個 RenderFragment。
在對外暴露組件時,Blazor 比 WinForm 要多一步,Blazor 中的 RenderFragment 是用於渲染組件的,不能通過 Control 屬性返回,同時我們也無法直接操作 RenderFragment,我們是通過 ComponentModel 間接操作 Blazor 組件渲染的,所以當我們在外部想自定義 PropertyEditor 中的組件時,WinForm 是直接操作 Control,而 Blazor 是通過 ComponentModel 來完成。
PropertyEditor 的大部分子類都是圍繞上面提到的屬性或方法進行封裝,以適應不同的平臺。對於 WinForm 來說相對比較簡單,就是直接操作 Control,而對於 Blazor 來說就要繁瑣一些,就因為這樣 XAF 針對 Blazor PropertyEditor 創建,做了大量的封裝,特別是在最新的24.1.3中丟棄了 ComponentAdapter,使 PropertyEditor 的創建更加簡單,甚至比 WinForm 還要簡潔一些。下麵主要以 Blazor 為主介紹 PropertyEditor 的相關技術點。
由於本文講的是 PropertyEditor 的原理,預設讀者是熟悉 PropertyEditor 的創建,所以不會再去講解 PropertyEditor 的創建過程,而是只講解它的技術點,如果對 PropertyEditor 的創建不熟悉的小伙伴,可以查看 XAF 的官方文檔。
在 XAF 新版本中 ComponentAdapter 被廢棄了,那它被引入的原因及被廢棄的原因是什麼呢?在 XAF Blazor 創建之初 ComponentAdapter 就已存在,通過它的名字我們知道它是一個代理層,負責 PropertyEditor 與 ComponentModel 之間的通訊。那為什麼要加入這個代理層呢,而不是 PropertyEditor 直接操作 ComponentModel 呢。這裡主要考慮是 PropertyEditor 的封裝,由於 PropertyEditor 的操作基本是固定的(如,讀值、寫值及一些常規屬性的設置),而 ComponentModel 是針對不同的組件的,不同的組件會有不同的屬性,比如類似值屬性,文本框是Text,日期框是Date,數值框是Value等,通過 ComponentAdapter 來適配不同的 ComponentModel(如:GetValue,SetValue 等),PropertyEditor 再去操作 ComponentAdapter ,這樣更利於 PropertyEditor 的封裝。
那在新版本中為什麼 ComponentAdapter 又被廢棄了呢,通過 XAF 的博客可以瞭解到,由於增加了 ComponentAdapter,使創建自定義 PropertyEditor 變的比較繁瑣,移除 ComponentAdapter 後,可以使 PropertyEditor 的創建更接近於 WinForm。在沒有了 ComponentAdapter 後,是不是 PropertyEditor 直接操作 ComponentModel 了呢,如果是那樣的話,就會出現前面所講到的,這會增加自定義 PropertyEditor 的複雜度,那新版是如何實現的呢。新版中是通過介面的方式來替代 ComponentAdapter,如新版中增加了一個 IHandleValueComponentModel 介面,通過這個介面 PropertyEditor 就可以獲取、更新或監聽組件值的變化,同時又增加了 DxComponentModelBase 這樣的一個基類,它包含了一些常用的屬性。也就是說新版是通過增加不同的介面及擴展基類的方式來替代 ComponentAdapter,這樣在簡化自定義 PropertyEditor 的同時,也保持了 PropertyEditor 的靈活性。
ComponentModel 在新版中還增加了一個 ComponentType 屬性,XAF 通過 ComponentType 屬性,可以自動完成 Renderer 的創建及屬性的賦值。在之前的版本中我們都是在 Renderer 中創建一個 Create 靜態方法,將 ComponentModel 傳遞進去,Renderer 需要將 ComponentModel 中的屬性一一賦值給組件,這個過程非常繁瑣,特別是 XAF 自身的 Renderer,代碼量非常的大。新版中通過 ComponentType 的組件類型實現組件自動創建的同時,還將 ComponentModel 的屬性自動傳遞給組件(提示:ComponentModel 的屬性要與組件的屬性保持一致)。由於 XAF 中的 PropertyEditor 都是對 Blazor 組件的封裝,在 XAF 中直接省掉了 Renderer,也就是在 XAF 中沒有 Renderer 的相關代碼了。
在新版中創建一個 Blazor PropertyEditor 則相當簡單,首先創建一個繼承自 DxComponentModelBase 的 ComponentModel,在 ComponentModel 中增加組件所需要的屬性,如果是自定義組件需要創建一個 Renderer,如果是 DEV 自身的 Blazor 組件,則直接將組件賦值給 ComponentType,同時基於 BlazorPropertyEditorBase 再創建一個 PropertyEditor,重寫 CreateComponentModel 方法,並返回 ComponentModel 實例,整個 PropertyEditor 創建過程就結束了,相對來說要比 WinForm 還要簡潔一些。
總結
在日常的 XAF 開發中,不管是增強或是個性化定製,都離不開 PropertyEditor,簡化 PropertyEditor 的創建過程,在降低創建 PropertyEditor 難度的同時,也能大幅提高自定義 PropertyEditor 在項目中的占比,提高用戶操作體驗。
https://www.cnblogs.com/haoxj/p/18255657