现在我要做的是:实现一个一对多关系的下拉属性编辑框。下拉框的要实现成树状结构。一开始我打算从ASPxLookupPropertyEditor继承,他是业务类型默认的属性编辑器。但是这一次有点麻烦,ASPxLookupPropertyEditor类包含的控件是 ASPxComboBox,ASPxComboBox控件中无法包含一颗树。因为绑定的是一个对象,而不是一个简单的值,所以上述列表中的 PropertyEditor的派生类都不适合。这一次我选择继承的是ASPxObjectPropertyEditorBase类。这是对象属性编辑器的基类。ASPxLookupPropertyEditor类就由这个类继承。
因为代码和方法相对比较少,重点只是在于你可能需要在好多个重写的方法中找到合适的那个,所以就不用画类图了。直接贴出代码:(再看代码的时候按所标注释的编号看,那是我完成代码的顺序)
001 [PropertyEditor()]//为了在上图的模型编辑器中会出现你自定义的编辑器,要加上这句代码。可以有参数,表示编辑器的数据类型。
002 public class ASPxTreePropertyEditor : ASPxObjectPropertyEditorBase
003 {
004
005 private WebLookupEditorHelper helper;
006 public ASPxTreePropertyEditor(Type objectType, IModelMemberViewItem model)
007 : base(objectType, model)
008 {
009 skipEditModeDataBind = true;
010 }
011 //1、集成了借口之后你需要实现的只有这一个重写方法,目的就在于要返回一个自定义的属性编辑器(也就是一个控件)
012 protected override WebControl CreateEditModeControlCore()
013 {
014 return CreateTreeDropDown();
015 }
016 TreeDropDown CreateTreeDropDown()
017 {
018 try
019 {
020 //2、具体的控件需要用到一个下拉书的控件,我在另一个类中实现了这个控件。
021 TreeDropDown treeDropDown = new TreeDropDown();
022
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();
031 col.Name = "Name";
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);
037 return treeDropDown;
038 }
039 catch (Exception e)
040 {
041 throw e;
042 }
043 }
044
045 //7、由于ASPxTreeList没有节点点击时间,所以我用了客户端的点击事件,让他返回一个回调方法。
046 void TreeList_CustomCallback(object sender, TreeListCustomCallbackEventArgs e)
047 {
048 //这里是用户在用户改变选择项的时候,重新为属性赋值。以保存对象。
049 ((TreeDropDown)Editor).Value = helper.GetObjectByKey(CurrentObject, e.Argument);
050 EditValueChangedHandler(sender, EventArgs.Empty);
051 }
052
053 // 6 、再绑定数据时需要用到一个helper对象,用来创建数据列表
054 public override void Setup(ObjectSpace objectSpace, XafApplication application)
055 {
056 base.Setup(objectSpace, application);
057 if (MemberInfo.IsPersistent)
058 {
059 helper = new WebLookupEditorHelper(application, objectSpace, MemberInfo.MemberTypeInfo, Model);
060 }
061 else
062 {
063 helper = new WebLookupNonPersistentEditorHelper(application, objectSpace, MemberInfo.MemberTypeInfo, Model);
064 }
065 }
066 }
067
068 //3、之后我生成了这个类。
069 class TreeDropDown : DevExpress.Web.ASPxEditors.ASPxDropDownEdit
070 {
071 ASPxTreeList treeList;
072 public ASPxTreeList TreeList
073 {
074 get
075 {
076 return treeList;
077 }
078 }
079
080 public TreeDropDown()
081 {
082
083 treeList = new ASPxTreeList();
084 //4、在这个类中我需要向他添加一个包含有ASPxTreeList控件的模板,所以要实现一个ITemplate接口
085 this.DropDownWindowTemplate = new TreeListTemplate(treeList);
086 }
087 protected override void OnPreRender(EventArgs e)
088 {
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);
095 }
096 function setDropDownText(value) {
097 DropDownEdit.SetText(value)
098 }</script> ";
099 this.RegisterScriptBlock("", script);
100 treeList.ClientSideEvents.NodeClick = "RowClickHandler";
101 base.OnPreRender(e);
102 }
103
104 //5、实现ITemplate接口完成一个模板项
105 class TreeListTemplate : ITemplate
106 {
107 ASPxTreeList treeList;
108 public TreeListTemplate(ASPxTreeList treeList)
109 {
110 this.treeList = treeList;
111 }
112 public void InstantiateIn(Control container)
113 {
114 container.Controls.Add(treeList);
115 }
116 }
117 }
可以看得出我写代码的时候不是一气呵成,而是从抽象的顶层,从外到里。你用XAF不得不如此,框架逼着你不得不这样。会后完成的东西就是这样:
最后是打包的源代码下载(我的的是XAF10.1.4版)。我没有提供数据库,你应当知道。那对XAF框架来说是不必要的,他会自动负责生成。可能你需要在下面这个界面输一些数据用于测试。
说明:本文原代码中,用了中文属性名和如上的代码注释,只是为了演示方便,并不代表我的编程风格。另:XAF是商业控件,所有代码演示所用的是官方下载的评估版本。