• C#用DesignSurface实现一个简单的窗体设计器


      System.ComponentModel.Design.DesignSurface是为设计组件提供一个用户界面,通过它可以实现一个简单的窗体设计器。

        在构建之前,我们需要引入System.Design.dll,否则会出现找不到DesignSurface的错误。

    private void Form1_Load(object sender, EventArgs e)
            {
               //引用System.Deisgn.dll
               DesignSurface ds = new DesignSurface();
                //开始加载窗体
                ds.BeginLoad(typeof(Form));
                Control designerContorl = (Control)ds.View;
                designerContorl.Dock = DockStyle.Fill;
                this.Controls.Add(designerContorl);
            }


    运行后出现简单的一个UI设计器

    但是该设计器并不能实现控件拖放和UI设计器,以及控件的属性配置。

    为了支持从源代码加载初始化窗体,需要对源码中的相关方法进行解析,这里我们 CodeDomDesignerLoader来实现定制化业务,CodeDomDesignerLoader是提供用于实现基于 CodeDOM 的设计器加载程序的基类。

    继承它的类需要重写CodeCompileUnit Parse()方法,来实现加载窗体:

    protected override CodeCompileUnit Parse()
            {
    
                #region 源文件读取
                var sw = new StreamReader(@"E:FrmUser.cs");
                var sw_designer = new StreamReader(@"E:FrmUser.Designer.cs");
    
                string formCodeCS = sw.ReadToEnd();
                string formCodeDesigner = sw_designer.ReadToEnd();
    
                List<string> source = new List<string>();
                source.Add(formCodeCS);
                source.Add(formCodeDesigner);
    
                #endregion
                //Rolsyn解析C#
                var rootDesigner = Source2CodeDom.Parse(formCodeDesigner);
                codeDesingerCompileUnit = Source2CodeDom.GetDesignerCodeComplieUnit(rootDesigner);
                var rootCS = Source2CodeDom.Parse(formCodeCS);
                codeCSCompileUnit = Source2CodeDom.GetCodeComplieUnit(rootCS);
                //MergeFormSource
                string mergeS = Source2CodeDom.MergeFormSource(formCodeDesigner, formCodeCS);
                codeMergeCompileUnit = Source2CodeDom.GetMergeDesignerCodeComplieUnit(mergeS);
                return codeMergeCompileUnit;

    解析的方法如下,但是此解析只是用于代码的生成,并不能用户UI界面的显示:

    public static CodeCompileUnit GetDesignerCodeComplieUnit2(CompilationUnitSyntax root)
            {
                CodeCompileUnit ccu = new CodeCompileUnit();
                var firstMember = root.Members[0];
                var namespaceDeclration = (NamespaceDeclarationSyntax)firstMember;
                var designClassDeclaration = (ClassDeclarationSyntax)namespaceDeclration.Members[0];
                var myDesignerClass = new CodeTypeDeclaration(designClassDeclaration.Identifier.ToString());
                var initializeComponent = new CodeMemberMethod();
                var ns = new CodeNamespace(namespaceDeclration.Name.ToString());
    
                foreach (var m in designClassDeclaration.Members)
                {
    
                    if (m is ConstructorDeclarationSyntax)
                    {
                        var ctor = ((ConstructorDeclarationSyntax)m);
                        var codeBody = ctor.Body.ToString();
                        codeBody = codeBody.Trim().TrimStart('{').TrimEnd('}').Trim().TrimEnd(';');
                        CodeSnippetExpression csbody = new CodeSnippetExpression(codeBody);
                        CodeExpressionStatement stmt = new CodeExpressionStatement(csbody);
                        //Add the expression statements to the method.
                        // InitializeComponent
                        var cctor = new CodeConstructor();
                        cctor.Name = ctor.Identifier.ToString();
                        //var cmm = new CodeMemberMethod();
                        //cmm.Name = ctor.Identifier.ToString();
                        //cmm.Attributes = GetCtoRAttrMapping(ctor);
                        //cmm.ReturnType = new CodeTypeReference(typeof(void));
                        cctor.Statements.Add(stmt);
    
                        myDesignerClass.Members.Add(cctor);
                    }
                    if (m is FieldDeclarationSyntax)
                    {
                        var F = ((FieldDeclarationSyntax)m);
                        var type = F.Declaration.Type;
                        foreach (var variable in F.Declaration.Variables)
                        {
                            var field = new CodeMemberField();
                            field.Name = variable.Identifier.ToString();
                            field.Type = new CodeTypeReference(type.ToString());
                            field.Attributes = GetFieldAttrMapping(F);
                            //field.InitExpression = new CodePrimitiveExpression(null);
                            myDesignerClass.Members.Add(field);
                        }
                    }
                    if (m is MethodDeclarationSyntax)
                    {
                        var node = m as MethodDeclarationSyntax;
                        #region xml comments
                        var xmlTrivia = node.GetLeadingTrivia()
                            .Select(i => i.GetStructure())
                            .OfType<DocumentationCommentTriviaSyntax>()
                            .FirstOrDefault();
    
    
    
                        #endregion
    
    
    
                        var method = (MethodDeclarationSyntax)m;
    
                        var cmm = new CodeMemberMethod();
                        cmm.Name = method.Identifier.ToString();
    
    
    
                        ///XML注释
                        string[] comments = xmlTrivia.ToString().Split("
    ".ToCharArray());
                        foreach (string text in comments)
                        {
                            if (text.Trim() != "")
                            {
                                cmm.Comments.Add(new CodeCommentStatement(text.Trim().TrimStart("///".ToCharArray()).Trim(), true));
                            }
                        }
    
    
    
                        if (cmm.Name == "InitializeComponent")
                        {
                            //region
                            CodeRegionDirective codeRegion = new CodeRegionDirective(CodeRegionMode.Start, "Windows 窗体设计器生成的代码");
                            CodeRegionDirective codeEndRegion = new CodeRegionDirective(CodeRegionMode.End, "");
    
                            cmm.StartDirectives.Add(codeRegion);
                            cmm.EndDirectives.Add(codeEndRegion);
                        }
    
                        //MemberAttributes.Family is protected
                        //cmm.Attributes = MemberAttributes.Override | MemberAttributes.Family;
                        cmm.Attributes = GetMethodAttrMapping(method);
                        cmm.ReturnType = new CodeTypeReference(method.ReturnType.ToString());
    
                        foreach (var p in method.ParameterList.Parameters)
                        {
                            CodeParameterDeclarationExpression cpd = new CodeParameterDeclarationExpression();
                            cpd.Name = p.Identifier.ToString();
    
                            cpd.Type = new CodeTypeReference(p.Type.ToString());
    
                            cmm.Parameters.Add(cpd);
                        }
                        //包含方法{};,会重复生成{};
                        string codeBody = method.Body.ToString();
                        codeBody = codeBody.Trim().TrimStart('{').TrimEnd('}').Trim().TrimEnd(';');
                        if (codeBody != "")
                        {
                            CodeSnippetExpression csbody = new CodeSnippetExpression(codeBody);
                            CodeExpressionStatement stmt = new CodeExpressionStatement(csbody);
                            //Add the expression statements to the method.
                            cmm.Statements.Add(stmt);
                        }
                        myDesignerClass.Members.Add(cmm);
    
                    }
                    if (m is MemberDeclarationSyntax)
                    {
    
                    }
                }
    
                ccu.Namespaces.Add(ns);
    
                //Partial Class
                myDesignerClass.IsPartial = true;
    
    
                ns.Types.Add(myDesignerClass);
    
    
    
                return ccu;
            }

     窗体的显示,需要逐句进行C#解析,特别是InitializeComponent()方法。

     

     CS Code其实最简单的就是读取源代码,然后返回就可以了。当设计器添加控件或者绑定事件时,可以通过文本操作进行代码完善。

    1 //直接返回代码,最简单
    2  public string GetTextCSCode()
    3  {
    4        Flush();
    5        return __CSTextCode;
    6 }

    CodeDomHostLoader类中有OnComponentRename,在设计器重命名组件时候响应,这里可以修复后台.cs中的控件引用

     

     

     但此设计器还有很多不完善的地方,后期有时间再完善吧。

    好的代码像粥一样,都是用时间熬出来的
  • 相关阅读:
    elementui form 相关表单验证
    函数注释备注
    elementui elform 某一值为数组,各项必填验证
    selenium等待的三种方式(详细)
    什么是python
    pytest基础
    pymysql数据库操作
    自动化测试1
    allure生成测试报告
    python读取excel的文件
  • 原文地址:https://www.cnblogs.com/jijm123/p/14165501.html
Copyright © 2020-2023  润新知