DevExpress XAF 根據業務類別屬性型別自動產生 UI 編輯器(字串→文字方塊、DateTime→日期選擇器、Enum→下拉清單、關聯物件→Lookup 下拉)。當內建編輯器無法滿足需求(如:一對多關聯需以樹狀結構呈現),需自訂 PropertyEditor。本文完整示範繼承 ASPxObjectPropertyEditorBase 實現樹狀下拉編輯器的全過程。
常用 Web 編輯器對應表:
| 屬性型別 | 預設編輯器 | UI 呈現 |
|---|---|---|
| String | ASPxStringPropertyEditor | 文字方塊 |
| Int32 | ASPxIntPropertyEditor | 數字輸入框 |
| Boolean | ASPxBooleanPropertyEditor | 核取方塊 |
| DateTime | ASPxDateTimePropertyEditor | 日期選擇器 |
| Enum | ASPxEnumPropertyEditor | 下拉清單 |
| 關聯物件 (BaseObject) | ASPxLookupPropertyEditor | 下拉清單 (含搜尋) |
編輯器對應關係儲存於 .xafml 模型檔(Application/Views/DetailView/Items/PropertyEditor 或 BOModel/Class/Member 節點),可透過模型編輯器視覺化修改。
PropertyEditor (抽象基類)
└── ASPxPropertyEditor (Web 專用)
└── ASPxObjectPropertyEditorBase (物件型別編輯器基類)
└── ASPxLookupPropertyEditor (內建 Lookup,使用 ASPxComboBox)
關鍵決策:ASPxLookupPropertyEditor 內部使用 ASPxComboBox,無法承載樹狀控制項。因此繼承 ASPxObjectPropertyEditorBase,自行構建包含 ASPxTreeList 的下拉編輯器。
[PropertyEditor(typeof(object), false)] // 註冊至模型編輯器,支援所有物件型別
public class ASPxTreePropertyEditor : ASPxObjectPropertyEditorBase
{
private WebLookupEditorHelper _helper;
public ASPxTreePropertyEditor(Type objectType, IModelMemberViewItem model)
: base(objectType, model)
{
SkipEditModeDataBind = true; // 手動控制資料繫結
}
// 1. 建立編輯模式控制項:回傳自訂下拉樹狀控制項
protected override WebControl CreateEditModeControlCore()
{
return CreateTreeDropDown();
}
private TreeDropDown CreateTreeDropDown()
{
var treeDropDown = new TreeDropDown();
// 2. 透過 Helper 取得關聯物件集合作為資料來源
treeDropDown.TreeList.DataSource = _helper.CreateListView(CurrentObject).CollectionSource.List;
treeDropDown.TreeList.KeyFieldName = "Oid";
treeDropDown.TreeList.ParentFieldName = "Parent!Key"; // 遞迴關聯欄位
treeDropDown.TreeList.ClientInstanceName = "TreeList";
treeDropDown.TreeList.Width = Unit.Percentage(100);
treeDropDown.ClientInstanceName = "DropDownEdit";
treeDropDown.TreeList.PreviewFieldName = "Name";
treeDropDown.TreeList.Columns.Add(new TreeListTextColumn { FieldName = "Name", Caption = "名稱" });
treeDropDown.ReadOnly = true; // 僅選擇,不直接編輯樹節點
treeDropDown.TreeList.SettingsBehavior.AutoExpandAllNodes = true;
treeDropDown.TreeList.CustomCallback += TreeList_CustomCallback; // 節點點選回呼
return treeDropDown;
}
// 7. 客戶端節點點選 → 伺服器回呼 → 更新屬性值
void TreeList_CustomCallback(object sender, TreeListCustomCallbackEventArgs e)
{
((TreeDropDown)Editor).Value = _helper.GetObjectByKey(CurrentObject, e.Argument);
EditValueChangedHandler(sender, EventArgs.Empty); // 通知 XAF 值已變更
}
// 6. Setup 階段建立 Helper(區分持久/非持久屬性)
public override void Setup(ObjectSpace objectSpace, XafApplication application)
{
base.Setup(objectSpace, application);
_helper = MemberInfo.IsPersistent
? new WebLookupEditorHelper(application, objectSpace, MemberInfo.MemberTypeInfo, Model)
: new WebLookupNonPersistentEditorHelper(application, objectSpace, MemberInfo.MemberTypeInfo, Model);
}
}
// 3. 自訂下拉控制項:繼承 ASPxDropDownEdit,內嵌 ASPxTreeList 模板
public class TreeDropDown : DevExpress.Web.ASPxEditors.ASPxDropDownEdit
{
private readonly ASPxTreeList _treeList = new ASPxTreeList();
public ASPxTreeList TreeList => _treeList;
public TreeDropDown()
{
// 4. 實作 ITemplate 將 TreeList 放入下拉視窗
DropDownWindowTemplate = new TreeListTemplate(_treeList);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
// 5. 註冊客戶端腳本:節點點選 → 設定下拉文字/值 → 關閉下拉 → 觸發伺服器回呼
const string script = @"
";
RegisterClientScriptBlock("TreeDropDownScript", script);
TreeList.ClientSideEvents.NodeClick = "RowClickHandler";
}
// 5. ITemplate 實作
private class TreeListTemplate : ITemplate
{
private readonly ASPxTreeList _treeList;
public TreeListTemplate(ASPxTreeList treeList) { _treeList = treeList; }
public void InstantiateIn(Control container) { container.Controls.Add(_treeList); }
}
}
下拉展開顯示完整樹狀階層,支援展開/摺疊、搜尋、節點選取回填。
完整 VS 2010 方案 (XAF 10.1.4) 含示例模組、資料庫自動建立:
XAF_TreePropertyEditor.rar
XAF 的屬性編輯器擴充機制雖有一定學習曲線,但遵循「從外而內、由框架引導」的實作順序(註冊屬性 → 建立控制項 → 模板嵌入 → 客戶端腳本 → 伺服器回呼 → Helper 整合),即可將任意複雜的 UI 需求無縫整合進自動化生成的業務介面中。此樹狀下拉編輯器模式可直接套用至組織架構、產品分類、權限樹等所有遞迴階層資料選擇場景。