动态添加基础资料控件原创
16人赞赏了该文章
3,531次浏览
编辑于2022年06月21日 10:43:07
关键词:动态,基础资料控件
一、需求
有些项目的单据需要根据条件展示不同的控件(尤其基础资料)以满足特殊的业务场景
二、思路与方案
2.1分析思路
实现这个功能有两种方式,一种是通过控件的显示隐藏,另一种方式是通过插件直接生成。前者明显是提前预置好的,给人的感觉是动态生成的,但其实本质不是动态的,需要提前知道有那些控件有多少控件要预置,不够灵活。而后者通过插件直接动态生成,优势是做到了真正的动态生成控件,不浪费存储资源和界面资源,十分灵活。本文讲述的是第二种方案
2.2实现方案
说到动态添加控件,就需要重写loadCustomControlMetas,beforeBindData,onGetControl,getEntityType方法,调整后台数据模型及数据包。这是必须要实现的
三、实现过程
1:表单注册插件,该插件继承AbstractFormPlugin
2、loadCustomControlMetas:向前端动态添加控件配置
/** * 界面显示前,触发此事件:向前端界面输出动态添加的字段、控件 * @remark * 这个事件只能向前端界面添加字段、控件;后台的视图模型、数据模型,均没有改变 */ @Override public void loadCustomControlMetas(LoadCustomControlMetasArgs e) { // TODO Auto-generated method stub super.loadCustomControlMetas(e); //建一个面板,并向其中动态添加字段、控件 FlexPanelAp headAp = this.createDynamicPanel(); Map<String, Object> mapHead = new HashMap<>(); mapHead.put(ClientProperties.Id, "kded_advconchildpanelap"); mapHead.put(ClientProperties.Items, headAp.createControl().get(ClientProperties.Items)); e.getItems().add(mapHead); }
3、beforeBindData:向界面编程模型,动态添加字段编程模型(FieldEdit)
/** * 此事件在把数据绑定到界面之前触发: * 系统会调用FormDataBinder对象,把字段值输出给前端字段编辑控件; * @param e * @remark * 动态添加的字段,在FormDataBinder中并没有记录,因此,默认不会绑定动态添加的字段值; * 必须在此事件,向FormDataBinder中注册动态添加的字段 */ @Override public void beforeBindData(EventObject e) { // TODO Auto-generated method stub super.beforeBindData(e); // 单据头添加的字段、控件,注入到容器面板的控件编程模型中 FlexPanelAp dynamicPanel = this.createDynamicPanel(); Container myFldPanel = this.getView().getControl("kded_advconchildpanelap"); myFldPanel.getItems().addAll(dynamicPanel.buildRuntimeControl().getItems()); this.getView().createControlIndex(myFldPanel.getItems()); }
4、onGetControl:创建动态控件的实例,并捕获控件事件
/** * 用户与自定义的控件进行交互时,会触发此事件 * @remark * 插件在此事件中,创建自定义控件的编程模型,并侦听其事件 */ @Override public void onGetControl(OnGetControlArgs e) { // TODO Auto-generated method stub super.onGetControl(e); if(e.getKey().equals("testbase")) { // 用户点击控件时,会触发此事件:创建基础资料的控件编程模型BasedataEdit实例返回 BasedataEdit baseEdit= new BasedataEdit(); baseEdit.setKey("testbase"); baseEdit.setView(this.getView()); e.setControl(baseEdit); } }
5、getEntityType:修改实体模型,增加属性
/** * 此事件在系统要用到表单主实体模型时触发 * @param e * @remark * 插件修改原始主实体,注册自定义属性,返回新的主实体给系统 */ @Override public void getEntityType(GetEntityTypeEventArgs e) { // 取原始的主实体 MainEntityType oldMainType = e.getOriginalEntityType(); // 复制主实体 MainEntityType newMainType = null; try{ newMainType = (MainEntityType)oldMainType.clone(); } catch (CloneNotSupportedException exp){ throw new KDException(exp, new ErrorCode("LoadCustomControlMetasSample", exp.getMessage())); } // 为自定义的文本字段,向主实体注册属性 this.registDynamicProps(newMainType); // 回传主实体给系统 e.setNewEntityType(newMainType); }
6、自定义封装的方法(动态添加控件,向实体注册属性)
/** * 创建一个面板,并向其中动态添加字段、控件 */ private FlexPanelAp createDynamicPanel(){ FlexPanelAp headPanelAp = new FlexPanelAp(); headPanelAp.setKey("headAp"); FieldAp fieldAp = new FieldAp(); fieldAp.setId("testbase"); fieldAp.setKey("testbase"); fieldAp.setName(new LocaleString("动态基础资料")); fieldAp.setFireUpdEvt(true); // 即时触发值更新事件 BasedataField ba=new BasedataField(); ba.setId("testbase"); ba.setKey("testbase"); ba.setBaseEntityId("bd_currency"); fieldAp.setField(ba); headPanelAp.getItems().add(fieldAp); return headPanelAp; } /** * 向主实体注册动态添加的属性 */ private void registDynamicProps(MainEntityType newMainType){ // 向单据头动态注册一个新的基础资料属性 BasedataProp bdpackPrp = new BasedataProp(); bdpackPrp.setDbIgnore(true); // bdpackPrp.setBaseEntityId("bd_material"); bdpackPrp.setName("testbase"); bdpackPrp.setDisplayName(new LocaleString("动态基础资料添加")); bdpackPrp.setAlias(""); bdpackPrp.setBaseEntityId("bd_currency"); EntityType dataEntityType = EntityMetadataCache.getDataEntityType("bd_currency"); bdpackPrp.setComplexType(dataEntityType); // 把新字段,注册到单据头 newMainType.addProperty(bdpackPrp); newMainType.registerComplexProperty(bdpackPrp); }
四 实现效果:
原单:并没有基础资料控件
动态添加后:
五、开发环境版本
v4.0.018.0
六、注意事项
1、实现步骤比较多,可以仔细看一下每一步的作用,如果少了一步就会导致功能无法生效
七、参考资料
Dtbase.rar(1.98KB)