转自:http://www.cnblogs.com/lauyee/archive/2010/06/21/1756978.html
XAF是什么,如果您没听说过,本文可能对你没有帮助,但如果你正在查找同样问题的解决方法希望对你有所帮助。(注:所举得例子全部是Web工程下的,Win工程原理相同)
XAF自动从业务类生成UI。自动的根据业务类各属性的类型生成所需的属性编辑器。比如,对于一个业务类中的String型的属性,生成的是一个文本框(从界面看是那样)。对Datetime型的属性生成一个日期选择框。
常用的属性编辑器类见下表(Web工程下):
| Tpye |
PropertyEditorType |
备注 |
| String |
DevExpress.ExpressApp.Web.Editors.ASPx.ASPxStringProertyEditor |
展示文本框 |
| Int32 |
DevExpress.ExpressApp.Web.Editors.ASPx.ASPxIntProertyEditor |
展示可调整的数字输入框 |
| Boolean |
DevExpress.ExpressApp.Web.Editors.ASPx.ASPxBooleanProertyEditor |
选中按钮 |
| Datetime |
DevExpress.ExpressApp.Web.Editors.ASPx.ASPxDatetimeProertyEditor |
时间框 |
| Enum |
DevExpress.ExpressApp.Web.Editors.ASPx.ASPxEnumProertyEditor |
下拉框 |
| <BaseObject> |
DevExpress.ExpressApp.Web.Editors.ASPx.ASPxLookupPropertyEditor |
下拉框,通常是同这个对象形成一对多的关系 |
在创建业务类的时候这些对象自动和业务类的属性关联,不需要再做声明。还可以选择其他的属性编辑器。可以在Xafml文件的Application | Views | Items | PropertyEditor节点或Application | Views | Items | PropertyEditor节点找到。如:
- 与 Rating 属性相应的 Application | Views | Items | PropertyEditor 节点:
<DetailView ID="Song_DetailView">
|
<PropertyEditor PropertyName="Rating" |
PropertyEditorType="MySolution.Module.Web.MySolutionAspNetModule.WebStarRatingPropertyEditor" />
|
- 与 Rating 属性相应的 Application | BOModel | Class | Member 节点:
<DetailView ID="Song_DetailView">
|
<PropertyEditor PropertyName="Rating" |
PropertyEditorType="MySolution.Module.Web.MySolutionAspNetModule.WebStarRatingPropertyEditor" />
|
当然最好的做法是用可视化的模型编辑器,也是可以在两个节点下找到,如图:


针对属性的类型不同,允许选择的类型不同。上图是字符串类型允许选择的属性编辑器。
所有的属性编辑器都要由PropertyEditor类继承。继承结构是这样的:

要实现一个自定义的属性编辑器,首先要确定从哪一个PropertyEditor的派生类继承,以及要是用的控件。
现在我要做的是:实现一个一对多关系的下拉属性编辑框。下拉框的要实现成树状结构。一开始我打算从ASPxLookupPropertyEditor继承,他是业务类型默认的属性编辑器。但是这一次有点麻烦,ASPxLookupPropertyEditor类包含的控件是ASPxComboBox,ASPxComboBox控件中无法包含一颗树。因为绑定的是一个对象,而不是一个简单的值,所以上述列表中的PropertyEditor的派生类都不适合。这一次我选择继承的是ASPxObjectPropertyEditorBase类。这是对象属性编辑器的基类。ASPxLookupPropertyEditor类就由这个类继承。
因为代码和方法相对比较少,重点只是在于你可能需要在好多个重写的方法中找到合适的那个,所以就不用画类图了。直接贴出代码:(再看代码的时候按所标注释的编号看,那是我完成代码的顺序)
002 |
public class ASPxTreePropertyEditor : ASPxObjectPropertyEditorBase
|
005 |
private WebLookupEditorHelper helper;
|
006 |
public ASPxTreePropertyEditor(Type objectType, IModelMemberViewItem model)
|
007 |
: base(objectType, model)
|
009 |
skipEditModeDataBind = true;
|
012 |
protected override WebControl CreateEditModeControlCore()
|
014 |
return CreateTreeDropDown();
|
016 |
TreeDropDown CreateTreeDropDown()
|
021 |
TreeDropDown treeDropDown = new TreeDropDown();
|
023 |
treeDropDown.TreeList.DataSource = helper.CreateListView(CurrentObject).CollectionSource.List;
|
024 |
treeDropDown.TreeList.KeyFieldName = "Oid";
|
025 |
treeDropDown.TreeList.ParentFieldName = "Parent!Key";
|
026 |
treeDropDown.TreeList.ClientInstanceName = "TreeList";
|
027 |
treeDropDown.TreeList.Width = Unit.Parse("100%");
|
028 |
treeDropDown.ClientInstanceName = "DropDownEdit";
|
029 |
treeDropDown.TreeList.PreviewFieldName = "Name";
|
030 |
TreeListTextColumn col = new TreeListTextColumn();
|
032 |
col.FieldName = "Name";
|
033 |
treeDropDown.TreeList.Columns.Add(col);
|
034 |
treeDropDown.ReadOnly = true;
|
035 |
treeDropDown.TreeList.SettingsBehavior.AutoExpandAllNodes = true;
|
036 |
treeDropDown.TreeList.CustomCallback += new TreeListCustomCallbackEventHandler(TreeList_CustomCallback);
|
046 |
void TreeList_CustomCallback(object sender, TreeListCustomCallbackEventArgs e)
|
049 |
((TreeDropDown)Editor).Value = helper.GetObjectByKey(CurrentObject, e.Argument);
|
050 |
EditValueChangedHandler(sender, EventArgs.Empty);
|
054 |
public override void Setup(ObjectSpace objectSpace, XafApplication application)
|
056 |
base.Setup(objectSpace, application);
|
057 |
if (MemberInfo.IsPersistent)
|
059 |
helper = new WebLookupEditorHelper(application, objectSpace, MemberInfo.MemberTypeInfo, Model);
|
063 |
helper = new WebLookupNonPersistentEditorHelper(application, objectSpace, MemberInfo.MemberTypeInfo, Model);
|
069 |
class TreeDropDown : DevExpress.Web.ASPxEditors.ASPxDropDownEdit
|
071 |
ASPxTreeList treeList;
|
072 |
public ASPxTreeList TreeList
|
080 |
public TreeDropDown()
|
083 |
treeList = new ASPxTreeList();
|
085 |
this.DropDownWindowTemplate = new TreeListTemplate(treeList);
|
087 |
protected override void OnPreRender(EventArgs e)
|
089 |
string script = @" <script type='text/javascript'>
|
090 |
function RowClickHandler(s, e) {
|
091 |
DropDownEdit.SetKeyValue(e.nodeKey);
|
092 |
TreeList.GetNodeValues(e.nodeKey, 'Name', setDropDownText);
|
093 |
DropDownEdit.HideDropDown();
|
094 |
TreeList.PerformCallback(e.nodeKey);
|
096 |
function setDropDownText(value) {
|
097 |
DropDownEdit.SetText(value)
|
099 |
this.RegisterScriptBlock("", script);
|
100 |
treeList.ClientSideEvents.NodeClick = "RowClickHandler";
|
105 |
class TreeListTemplate : ITemplate
|
107 |
ASPxTreeList treeList;
|
108 |
public TreeListTemplate(ASPxTreeList treeList)
|
110 |
this.treeList = treeList;
|
112 |
public void InstantiateIn(Control container)
|
114 |
container.Controls.Add(treeList);
|
可以看得出我写代码的时候不是一气呵成,而是从抽象的顶层,从外到里。你用XAF不得不如此,框架逼着你不得不这样。会后完成的东西就是这样:

最后是打包的源代码下载(我的的是XAF10.1.4版)。我没有提供数据库,你应当知道。那对XAF框架来说是不必要的,他会自动负责生成。可能你需要在下面这个界面输一些数据用于测试。

说明:本文原代码中,用了中文属性名和如上的代码注释,只是为了演示方便,并不代表我的编程风格。另:XAF是商业控件,所有代码演示所用的是官方下载的评估版本。