XAF中的自定义属性编辑器


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 节点:

<Application> 
   <Views> 
      <DetailView ID="Song_DetailView"> 
         <Items> 
            <PropertyEditor PropertyName="Rating" 
               PropertyEditorType="MySolution.Module.Web.MySolutionAspNetModule.WebStarRatingPropertyEditor" /> 
         </Items> 
      </DetailView> 
   </Views> 
</Application> 

  与 Rating 属性相应的 Application | BOModel | Class | Member 节点:

<Application> 
   <Views> 
      <DetailView ID="Song_DetailView"> 
         <Items> 
            <PropertyEditor PropertyName="Rating" 
               PropertyEditorType="MySolution.Module.Web.MySolutionAspNetModule.WebStarRatingPropertyEditor" /> 
         </Items> 
      </DetailView> 
   </Views> 
</Application> 

  当然最好的做法是用可视化的模型编辑器,也是可以在两个节点下找到,如图:

  针对属性的类型不同,允许选择的类型不同。上图是字符串类型允许选择的属性编辑器。

  所有的属性编辑器都要由PropertyEditor类继承。继承结构是这样的:

  要实现一个自定义的属性编辑器,首先要确定从哪一个PropertyEditor的派生类继承,以及要是用的控件。

  现在我要做的是:实现一个一对多关系的下拉属性编辑框。下拉框的要实现成树状结构。一开始我打算从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是商业控件,所有代码演示所用的是官方下载的评估版本

本文示例源代码或素材下载


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3