二开-表单插件-代码创建控件原创
金蝶云社区-墨白64
墨白64
66人赞赏了该文章 445次浏览 未经作者许可,禁止转载编辑于2023年11月03日 17:28:01
封面
  • 一,开发功能介绍

        首先介绍开发功能,通过C#代码修改元数据的形式去动态创建控件,目前已实现功能: 在一个动态表单上采用代码构建出控件。目前已经实现通过代码创建出单据体,文本,分组标题等控件。别问为什么去做这些功能,问就是闲的。

        直接上代码,具体的控件构建代码直接看元数据操作辅助类--MetadataUtils

        也是参照大佬的帖子 做出来的 详情贴:https://vip.kingdee.com/article/128545166554105344?productLineId=1

        如果有帮助,给我点点收藏+点赞哦


using Kingdee.BOS;
using Kingdee.BOS.Core.DynamicForm;
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel;
using Kingdee.BOS.Core.Metadata;
using Kingdee.BOS.Core.Metadata.ControlElement;
using Kingdee.BOS.Core.Metadata.ElementMetadata;
using Kingdee.BOS.Core.Metadata.EntityElement;
using Kingdee.BOS.Core.Metadata.FieldElement;
using Kingdee.BOS.Core.Metadata.Util;
using Kingdee.BOS.JSON;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.Orm.Metadata.DataEntity;
using Kingdee.BOS.ServiceHelper;
using Kingdee.BOS.Util;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace BL.K3.Plugln.Bill.ENGRouteProcess
{
    [Description("二开-【动态表单插件】-动态表单动态构建工艺参数展示数据"), HotUpdate]
    public class EngProcessPanel : AbstractDynamicFormPlugIn
    {
        #region var        
        /// <summary>
        /// 动态表格的表头布局元数据
        /// </summary>
        private LayoutInfo dynamicLayoutInfo = new LayoutInfo();
        /// <summary>
        /// 动态表格的表体布局元数据
        /// </summary>
        private List<LayoutInfo> dynamicEntityLayoutInfo = new List<LayoutInfo>();
        private List<Appearance> listAppearance = new List<Appearance>();
        private List<Field> listField = new List<Field>();
        private List<Entity> listEntity = new List<Entity>();
        private string entrykey = string.Empty;
        private List<object> ProIds =new List<object>();
        #endregion
        public override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            var parentPanel = this.View.GetControl<Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel.Container>("F_QPUB_Panel");
            parentPanel.AddControls(this.dynamicLayoutInfo);            
            foreach (var entity in this.listEntity)
            {
                //给表格动态创建列
                var gridAP = this.View.LayoutInfo.GetEntryEntityAppearance(entity.Key);
                var entryGrid = this.View.GetControl<EntryGrid>(entity.Key);
                entryGrid.CreateDyanmicList(gridAP);
                entryGrid.Enabled = true;
            }
        }
        public override void OnInitializeService(InitializeServiceEventArgs e)
        {
            base.OnInitializeService(e);
            this.dynamicLayoutInfo = new LayoutInfo();
            //获取对应选中工序序列的数据包
            var EntiData = (DynamicObject)this.View.OpenParameter.GetCustomParameter("data");           
            //若未获取到数据包
            if (EntiData.IsNullOrEmptyOrWhiteSpace() || EntiData == null || EntiData.ToString() == "0") return;
            //获取工序序列对应序列名称
            var SeqName = (EntiData["SeqName"] as LocaleValue).GetString(2052);
            //获取对应的工序明细
            var DetailData = (DynamicObjectCollection)EntiData["RouteOperDetail"];
            int topxy = 10;
            int i = 0;
            //遍历明细 获取所有的工序作业数据包
            foreach (var detail in DetailData)
            {
                bool first = false; //控制首次创建标题字段
                int J = 0; //控制循环次数     
                if (detail["ProcessId"].IsNullOrEmptyOrWhiteSpace()) continue;
                //获取对应作业行的工序号
                var operNumber = detail["OperNumber"].ToString();
                //获取对应的作业数据包
                //var workData = (DynamicObject)detail["ProcessId"];
                FormMetadata meta = MetaDataServiceHelper.Load(this.Context, "ENG_Process") as FormMetadata;
                var workData = BusinessDataServiceHelper.LoadSingle(this.Context, detail["ProcessId_Id"], meta.BusinessInfo.GetDynamicObjectType());
                if (workData.IsNullOrEmptyOrWhiteSpace()) continue;
                var workname = (workData["name"] as LocaleValue).GetString(2052);
                //用一个object数组存放 序列名称 工序号 作业名称 参数标识 参数类型 参数名 
                object[] proxy = new object[8];
                proxy[0] = SeqName;                                          //工序序列-序列名称
                proxy[1] = operNumber;                                       //工序明细-工序号
                proxy[2] = workname;                                         //工序明细-作业名称
                proxy[3] = workData["number"];                               //工序明细-作业编码
                proxy[4] = detail["id"];                                     //工序明细-工序内码
                this.ProIds.Add(detail["id"]);
                //获取作业对应的作业参数
                var workPara = workData["FParaterEntity"] as DynamicObjectCollection;         
                //若对应的作业参数数据包不为空,正常添加内容,否则只添加一个标题控件
                if (!workPara.IsNullOrEmptyOrWhiteSpace() && workData["FParaterEntity"] != null &&workPara.Count!=0)
                {
                    foreach (var para in workPara.OrderBy(p => p["F_BL_ParameterTypes"].Equals("单据体") ? 1 : 0).ToList())
                    {                        
                        proxy[5] = para["F_BL_ParameterId"];                         //作业参数-参数标识
                        proxy[6] = para["F_BL_ParameterTypes"];                      //作业参数-参数类型
                        proxy[7] = para["F_BL_parameterName"];                       //作业参数-参数名
                        //首先第一次创建一个分组标题字段
                        if (!first)
                        {
                            topxy += 25;
                            CreateGroupTitle(topxy, proxy);
                            first = true;
                            i++;
                        }
                        //参数类型非单据体
                        if (!proxy[6].Equals("单据体"))
                        {
                            if (J % 2 == 0) topxy += 25;
                            //表头字段
                            var fieldName = string.Format("{0}_{1}", proxy[5], proxy[4]);//字段标识: 参数标识_工序明细内码
                            var fieldCapt = string.Format("{0}_{1}", proxy[7], proxy[2]);//字段名称: 参数名_作业名称
                            var field = MetadataUtils.CreateField<TextField, TextFieldAppearance>(this.Context, this.View, "FBillHead", fieldName, fieldCapt, topxy, J % 2 * 280);
                            this.listAppearance.Add(field);
                            this.listField.Add(field.Field);
                            this.dynamicLayoutInfo.Add(field);
                            if (J % 2 == 1) i++;
                            J++;
                        }
                        //创建单据体表体
                        else
                        {
                            topxy += 25;
                            var entiid = string.Format("{0}_{1}", proxy[5], proxy[4]);     //单据体标识-需要拿该标识去工艺参数元数据中匹配查找表对应的元数据
                            var panelid = string.Format("F_BL_PANEL_{0}", proxy[4]);       
                            var entiName = proxy[7].ToString();   //单据体名称
                            var panel = MetadataUtils.CreatePanel(this.Context, this.View, panelid, panelid, topxy);
                            this.listAppearance.Add(panel);
                            var entity = MetadataUtils.CreateEntity<EntryEntity, EntryEntityAppearance>(this.Context, this.View, entiid, entiName, panelid);                            
                            this.listAppearance.Add(entity);
                            this.listEntity.Add(entity.Entity);
                            this.dynamicLayoutInfo.Add(panel);
                            this.dynamicLayoutInfo.Add(entity);
                            i++;
                            //动态构建单据体的字段内容
                            //1.获取工艺参数单据的元数据用于动态构建单据体
                            var paraMeta = MetaDataServiceHelper.GetFormMetaData(this.Context, "QPUB_BL_Parameter");
                            var entityName = proxy[5].ToString();
                            //获取指定单据体的数据包
                            var entityBussin = paraMeta.BusinessInfo.GetEntity(entityName);
                            var fieldList = entityBussin.Fields.Select(o => o).ToList();
                            var metadataCopy = (FormMetadata)ObjectUtils.CreateCopy(this.View.OpenParameter.FormMetaData);
                            //动态创建Businesslnfo
                            var businesslnfo = metadataCopy.BusinessInfo;
                            Entity enti = businesslnfo.GetEntity(entityName);
                            if(this.entrykey.IsNullOrEmptyOrWhiteSpace()) this.entrykey = entiid;
                            for (int k = 0; k < fieldList.Count; k++)
                            {
                                var fieldAp = MetadataUtils.CreateEntityField<TextField, TextFieldAppearance>(this.Context, this.View, fieldList[k], enti, entiid, k);
                                this.listAppearance.Add(fieldAp);
                                this.listField.Add(fieldAp.Field);
                                this.dynamicLayoutInfo.Add(fieldAp);
                            }
                            topxy += 300;
                        }
                    }
                    if (J % 2 == 1) i++;
                }
                else
                {
                    topxy += 25;
                    CreateGroupTitle(topxy, proxy);
                    i++;
                }
            }           
        }
        /// <summary>
        /// 初始化当前动态表单的数据包
        /// </summary>
        /// <param name="e"></param>
        public override void BeforeBindData(EventArgs e)
        {
            base.BeforeBindData(e);                       
            this.Model.DataObject = new DynamicObject(this.View.BusinessInfo.GetDynamicObjectType());            
        }
        public override void AfterBindData(EventArgs e)
        {
            base.AfterBindData(e);
            //获取对应选中工序序列的数据包
            var EntiData = (DynamicObject)this.View.OpenParameter.GetCustomParameter("data");
            //若未获取到数据包 则返回
            if (EntiData.IsNullOrEmptyOrWhiteSpace()) return;
            this.SetData();
        }
        /// <summary>
        /// 动态设置表单业务元数据
        /// </summary>
        /// <param name="e"></param>
        public override void OnSetBusinessInfo(SetBusinessInfoArgs e)
        {
            base.OnSetBusinessInfo(e);            
            // 动态创建businessinfo,先移除后添加
            var businessInfo = (BusinessInfo)ObjectUtils.CreateCopy(this.View.BusinessInfo);
            foreach (var field in this.listField)
            {
                businessInfo.Remove(field);
            }
            foreach (var entity in this.listEntity)
            {
                businessInfo.Remove(entity);
            }
            foreach (var entity in this.listEntity)
            {
                businessInfo.Add(entity);
            }
            foreach (var field in this.listField)
            {
                businessInfo.Add(field);
            }
            
            //修改了元数据,重新生成该元数据的类型定义
            businessInfo.GetDynamicObjectType(true);
            e.BusinessInfo = businessInfo;
            e.BillBusinessInfo = businessInfo;
        }
        /// <summary>
        /// 动态设置表单布局元数据
        /// </summary>
        /// <param name="e"></param>
        public override void OnSetLayoutInfo(SetLayoutInfoArgs e)
        {
            base.OnSetLayoutInfo(e);              
            //动态创建LayoutInfo
            var layoutInfo = (LayoutInfo)ObjectUtils.CreateCopy(this.View.LayoutInfo);
            foreach (var item in this.listAppearance)
            {
                layoutInfo.Remove(item);
            }
            foreach (var appearances in this.listAppearance)
            {
                layoutInfo.Add(appearances);
            }
            e.LayoutInfo = layoutInfo;
            e.BillLayoutInfo = layoutInfo;
        }
        //给构建出来的表头字段和表体字段进行赋值操作
        private void SetData()
        { 
            //遍历明细数据包,获取当前工序明细行作业的Id集合
            //拿对应的Id去查询对应配置的工艺参数的数据包,将其中的数据赋值到对应字段当中
            foreach (var id in this.ProIds)
            {
                //查询当前明细行作业对应的工艺参数单据内码
                string sql = string.Format(@"/*dialect*/select fid from T_BL_ProcessParameter where FPROCESSID='{0}'", id);
                var result = DBServiceHelper.ExecuteDynamicObject(this.Context, sql);
                if (result.Count > 0)
                {
                    //获取指定工艺参数的数据包,用于给表头字段赋值
                    FormMetadata meta = MetaDataServiceHelper.Load(this.Context, "QPUB_BL_Parameter") as FormMetadata;
                    var Pamadata = BusinessDataServiceHelper.LoadSingle(this.Context, result[0]["fid"], meta.BusinessInfo.GetDynamicObjectType());
                    //获取当前工序明细行已配置的字段,赋值
                    var headFields = this.View.BusinessInfo.GetEntity("FBillHead").Fields.FindAll(o => o.PropertyName.Contains(id.ToString())).Select(o => o.PropertyName).ToList();
                    //获取工序序列明细配置的字段
                    var metaFields = meta.BusinessInfo.GetEntity("FBillHead").Fields;
                    foreach (var heafid in headFields)
                    {
                        var propertyName = heafid.Replace("_" + id, "");
                        var field = metaFields.First(o => o.PropertyName.EqualsIgnoreCase(propertyName));
                        this.View.Model.SetValue(heafid, ReturnDataValue(Pamadata[propertyName], field));
                        this.View.UpdateView(heafid);
                    }
                    this.View.BusinessInfo.GetDynamicObjectType(true);  
                    //构建表体行字段数值
                    foreach(var entity in this.listEntity)
                    {
                        string entityKey = entity.Key.Replace("_" + id, "");
                        var entryGrid = this.View.GetControl<EntryGrid>(entity.Key);
                        entryGrid.SetAllowLayoutSetting(false);
                        entryGrid.SetData(GetEntityData(Pamadata, entityKey));
                        //下达一个指令
                        this.View.SendDynamicFormAction(this.View);  
                    }
                }
            }
        }
        //构建单据体表格数据
        private JSONObject GetEntityData(DynamicObject dynamicObject, String entity)
        {
            var objdata = new JSONObject();
            var rows = new JSONArray();
            if (!dynamicObject.Contains(entity)) return null;
            //获取工艺参数单据的元数据用于动态构建单据体
            var paraMeta = MetaDataServiceHelper.GetFormMetaData(this.Context, "QPUB_BL_Parameter");
            //获取指定单据体的数据包
            var entityBussin = paraMeta.BusinessInfo.GetEntity(entity);
            var fieldList = entityBussin.Fields.Select(o => o).ToList();
            var dynamicObjectCollection = dynamicObject[entity] as DynamicObjectCollection;
            if (dynamicObjectCollection.Count > 0)
            {
                int x = 0;
                foreach (var obj in dynamicObjectCollection)
                {
                    var row = new JSONArray();
                    row.Add(x);
                    for (int i = 0; i < fieldList.Count; i++)
                    {
                        row.Add(this.ReturnDataValue(obj[fieldList[i].Key], fieldList[i]));
                    }
                    rows.Add(row);
                    x++;
                }
                objdata.Put("rows", rows);
            }
            return objdata;
        }
        //动态构造一个分组标题字段
        private void CreateGroupTitle(int top ,object[] proxy)
        {
            //标题:序列名称_工序号_作业名称
            var titleName = string.Format("{0}_{1}_{2}", proxy[0], proxy[1], proxy[2]);
            var titleAp = new GroupTitleAppearance();
            titleAp.Id = Guid.NewGuid().ToString();
            //标题key: 标识_作业编码
            titleAp.Key = string.Format("F_BL_GropTitle_{0}", proxy[3]);
            titleAp.LabelWidth = new LocaleValue("70", this.Context.UserLocale.LCID);
            titleAp.Width = new LocaleValue("550", this.Context.UserLocale.LCID);
            titleAp.Caption = new LocaleValue(titleName, this.Context.UserLocale.LCID);
            titleAp.Top = new LocaleValue(top.ToString(), this.Context.UserLocale.LCID);
            titleAp.Left = new LocaleValue("0", this.Context.UserLocale.LCID);
            this.listAppearance.Add(titleAp);
            this.dynamicLayoutInfo.Add(titleAp);
        }
        //处理源单不同字段类型的赋值情况
        private object ReturnDataValue(object obj, Field field)
        {
            Type type = field.GetType();
            switch (type.Name)
            {
                case "AssistantField"://单选辅助基础资料
                    if (!obj.IsNullOrEmptyOrWhiteSpace()) obj = ((DynamicObject)obj)["FDataValue"].ToString();
                    break;
                case "BaseDataField"://基础资料
                    if (!obj.IsNullOrEmptyOrWhiteSpace()) obj = ((DynamicObject)obj)["Number"];
                    break;
                case "ComboField"://下拉列表
                    if (obj.IsNullOrEmptyOrWhiteSpace() || obj.ToString() == "")
                    {
                        obj = string.Empty;
                    }
                    else
                    {
                        //根据枚举值获取枚举项,然后拿枚举项的枚举名称
                        ComboField comboField = field as ComboField;
                        var enumObj = (EnumObject)comboField.EnumObject;
                        obj = enumObj.Items.FirstOrDefault(p => p.Value.Equals(obj.ToString())).Caption.GetString(this.Context.UserLocale.LCID);
                    }
                    break;
                default:
                    break;
            }
            return obj;
        }
        //元数据操作辅助类
        public static class MetadataUtils
        {
            ///创建字段
            public static TFieldAppearance CreateField<TField, TFieldAppearance>(Context ctx, IDynamicFormView view, string entityKey, string fieldName, string caption, int top = 0, int left = 0)
                where TFieldAppearance : FieldAppearance, new()
                where TField : Field, new()
            {
                string fieldId = Guid.NewGuid().ToString();
                //创建字段
                var field = new TField();
                field.Entity = view.BusinessInfo.GetEntity(entityKey);
                field.FieldName = fieldName;   
                field.Id = fieldId;
                field.Key = fieldName;              
                field.EntityKey = entityKey;
                field.Name = new LocaleValue(caption, ctx.UserLocale.LCID);                            
                field.PropertyName = fieldName;
                field.MaxDataScope = 50;                
                //创建字段外观
                var fieldAppearance = new TFieldAppearance();
                fieldAppearance.Field = field;
                fieldAppearance.Id = fieldId;
                fieldAppearance.Key = fieldName;                
                fieldAppearance.EntityKey = entityKey;
                fieldAppearance.Caption = field.Name;
                fieldAppearance.Locked = -1;
                fieldAppearance.LabelWidth = new LocaleValue("100", ctx.UserLocale.LCID);
                fieldAppearance.Width = new LocaleValue("300", ctx.UserLocale.LCID);
                fieldAppearance.Top = new LocaleValue(top.ToString(), ctx.UserLocale.LCID);
                fieldAppearance.Left = new LocaleValue(left.ToString(), ctx.UserLocale.LCID);
                FieldRegisterDynamicProperty(fieldAppearance.Field, new DynamicObjectType(fieldName));
                return fieldAppearance;
            }
            //创建单据体
            public static TEntryEntityApprearance CreateEntity<TEntryEntity, TEntryEntityApprearance>(Context ctx, IDynamicFormView view, string entityKey, string entityName, string panelKey, int top = 0, int left = 0)
                where TEntryEntityApprearance : EntryEntityAppearance, new()
                where TEntryEntity : EntryEntity, new()
            {
                //var entry = (EntryEntity)view.BusinessInfo.GetEntryEntity("F_BL_Entity").Clone();
                var entry = new TEntryEntity();
                entry.EntryName = entityKey;
                entry.Id = Guid.NewGuid().ToString();
                entry.Name = new LocaleValue(entityName, ctx.UserLocale.LCID);
                entry.Key = entityKey;
                entry.DefaultRows = 0;
                entry.ElementType = 35;
                entry.DynamicObjectType = new DynamicObjectType(entityKey); 
                var entryAppearance = new TEntryEntityApprearance();
                entryAppearance.Id = Guid.NewGuid().ToString();
                entryAppearance.Key = entityKey;
                entryAppearance.Caption = entry.Name;
                entryAppearance.EntityKey = entityKey;
                entryAppearance.Dock = 5;
                entryAppearance.Container = panelKey.ToUpper();
                entryAppearance.Locked = -1;
                entryAppearance.Entity = entry;
                entryAppearance.ElementType = 35;
                //entryAppearance.Height = new LocaleValue("30", ctx.UserLocale.LCID);
                entryAppearance.Top = new LocaleValue(top.ToString(), ctx.UserLocale.LCID);
                entryAppearance.Left = new LocaleValue("0", ctx.UserLocale.LCID);
                entryAppearance.LabelWidth = new LocaleValue("25", ctx.UserLocale.LCID);
                //entryAppearance.Width = new LocaleValue("500", ctx.UserLocale.LCID);
                EntityRegisterDynamicProperty(entryAppearance.Entity, new DynamicObjectType(entityKey));
                return entryAppearance;
            }

            //创建单据体
            public static PanelAppearance CreatePanel(Context ctx, IDynamicFormView view, string entityKey, string entityName, int top = 0, int left = 0)
            {
                PanelAppearance panelAppearance = new PanelAppearance();
                panelAppearance.Id = Guid.NewGuid().ToString();
                panelAppearance.Key = entityKey;
                panelAppearance.EntityKey = entityKey;
                panelAppearance.Locked = -1;
                panelAppearance.Hscroll = 2;
                panelAppearance.Height = new LocaleValue("300", ctx.UserLocale.LCID);
                panelAppearance.Top = new LocaleValue(top.ToString(), ctx.UserLocale.LCID);
                panelAppearance.Left = new LocaleValue("0", ctx.UserLocale.LCID);
                panelAppearance.Width = new LocaleValue("550", ctx.UserLocale.LCID);
                return panelAppearance;
            }

            //创建单据体的字段内容
            public static TFieldAppearance CreateEntityField<TField, TFieldAppearance>(Context ctx, IDynamicFormView view, Field Field, Entity entity, string entityName,int k)
                where TFieldAppearance : FieldAppearance, new()
                where TField : Field, new()
            {
                //重新构建单据体字段,构建文本字段   
                string fieldId = Guid.NewGuid().ToString();
                var fld = new TextField();
                fld.Key = String.Format(Field.Key);
                fld.Id = fieldId;
                fld.Name = new LocaleValue(Field.Name);
                fld.PropertyName = String.Format(Field.Key);
                fld.EntityKey = entityName;
                fld.Entity = entity;
                fld.FireUpdateEvent = 0;
                TFieldAppearance fldApp = new TFieldAppearance();
                fldApp.Key = fld.Key;
                fldApp.Caption = fld.Name;
                fldApp.EntityKey = fld.EntityKey;
                fldApp.Width = new LocaleValue("60");
                fldApp.LabelWidth = new LocaleValue("60");
                fldApp.Tabindex = k;
                fldApp.Field = fld;
                fldApp.TextEditStyle = 1;
                fldApp.Id = fieldId;
                MetadataUtils.FieldRegisterDynamicProperty(fld, new DynamicObjectType("f_text"));
                return fldApp;
                
                
            }
            /// <summary>
            /// 给字段动态注册属性
            /// </summary>
            /// <param name="field"></param>
            /// <param name="dynamicObjectType"></param>
            public static void FieldRegisterDynamicProperty(Field field, DynamicObjectType dynamicObjectType)
            {
                var methodInfo = field.GetType().GetMethod("RegisterDynamicProperty", BindingFlags.Instance | BindingFlags.NonPublic);
                if (methodInfo == null)
                {
                    return;
                }
                methodInfo.Invoke(field, new object[] { dynamicObjectType });
            }

            public static void EntityRegisterDynamicProperty(Entity entity, DynamicObjectType dynamicObjectType)
            {
                var methodInfo = entity.GetType().GetMethod("RegisterDynamicProperty", BindingFlags.Instance | BindingFlags.NonPublic);
                if (methodInfo == null)
                {
                    return;
                }
                methodInfo.Invoke(entity, new object[] { dynamicObjectType });
            } 
        }
    }
}

        

赞 66