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


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

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

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

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

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

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

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

     1         protected override CodeCompileUnit Parse()
     2         {
     3          
     4             #region 源文件读取
     5             var sw = new StreamReader(@"E:FrmUser.cs");
     6             var sw_designer = new StreamReader(@"E:FrmUser.Designer.cs");
     7 
     8             string formCodeCS = sw.ReadToEnd();
     9             string formCodeDesigner = sw_designer.ReadToEnd();
    10 
    11             List<string> source = new List<string>();
    12             source.Add(formCodeCS);
    13             source.Add(formCodeDesigner);
    14 
    15             #endregion
    16             //Rolsyn解析C#
    17             var rootDesigner = Source2CodeDom.Parse(formCodeDesigner);
    18             codeDesingerCompileUnit = Source2CodeDom.GetDesignerCodeComplieUnit(rootDesigner);
    19             var rootCS = Source2CodeDom.Parse(formCodeCS);
    20             codeCSCompileUnit = Source2CodeDom.GetCodeComplieUnit(rootCS);
    21             //MergeFormSource
    22             string mergeS = Source2CodeDom.MergeFormSource(formCodeDesigner, formCodeCS);
    23             codeMergeCompileUnit = Source2CodeDom.GetMergeDesignerCodeComplieUnit(mergeS);
    24             return codeMergeCompileUnit;

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

      1        public static CodeCompileUnit GetDesignerCodeComplieUnit2(CompilationUnitSyntax root)
      2         {
      3             CodeCompileUnit ccu = new CodeCompileUnit();
      4             var firstMember = root.Members[0];
      5             var namespaceDeclration = (NamespaceDeclarationSyntax)firstMember;
      6             var designClassDeclaration = (ClassDeclarationSyntax)namespaceDeclration.Members[0];
      7             var myDesignerClass = new CodeTypeDeclaration(designClassDeclaration.Identifier.ToString());
      8             var initializeComponent = new CodeMemberMethod();
      9             var ns = new CodeNamespace(namespaceDeclration.Name.ToString());
     10 
     11             foreach (var m in designClassDeclaration.Members)
     12             {
     13 
     14                 if (m is ConstructorDeclarationSyntax)
     15                 {
     16                     var ctor = ((ConstructorDeclarationSyntax)m);
     17                     var codeBody = ctor.Body.ToString();
     18                     codeBody = codeBody.Trim().TrimStart('{').TrimEnd('}').Trim().TrimEnd(';');
     19                     CodeSnippetExpression csbody = new CodeSnippetExpression(codeBody);
     20                     CodeExpressionStatement stmt = new CodeExpressionStatement(csbody);
     21                     //Add the expression statements to the method.
     22                     // InitializeComponent
     23                     var cctor = new CodeConstructor();
     24                     cctor.Name = ctor.Identifier.ToString();
     25                     //var cmm = new CodeMemberMethod();
     26                     //cmm.Name = ctor.Identifier.ToString();
     27                     //cmm.Attributes = GetCtoRAttrMapping(ctor);
     28                     //cmm.ReturnType = new CodeTypeReference(typeof(void));
     29                     cctor.Statements.Add(stmt);
     30 
     31                     myDesignerClass.Members.Add(cctor);
     32                 }
     33                 if (m is FieldDeclarationSyntax)
     34                 {
     35                     var F = ((FieldDeclarationSyntax)m);
     36                     var type = F.Declaration.Type;
     37                     foreach (var variable in F.Declaration.Variables)
     38                     {
     39                         var field = new CodeMemberField();
     40                         field.Name = variable.Identifier.ToString();
     41                         field.Type = new CodeTypeReference(type.ToString());
     42                         field.Attributes = GetFieldAttrMapping(F);
     43                         //field.InitExpression = new CodePrimitiveExpression(null);
     44                         myDesignerClass.Members.Add(field);
     45                     }
     46                 }
     47                 if (m is MethodDeclarationSyntax)
     48                 {
     49                     var node = m as MethodDeclarationSyntax;
     50                     #region xml comments
     51                     var xmlTrivia = node.GetLeadingTrivia()
     52                         .Select(i => i.GetStructure())
     53                         .OfType<DocumentationCommentTriviaSyntax>()
     54                         .FirstOrDefault();
     55 
     56        
     57 
     58                     #endregion
     59 
     60 
     61 
     62                     var method = (MethodDeclarationSyntax)m;
     63 
     64                     var cmm = new CodeMemberMethod();
     65                     cmm.Name = method.Identifier.ToString();
     66 
     67 
     68 
     69                     ///XML注释
     70                     string[] comments = xmlTrivia.ToString().Split("
    ".ToCharArray());
     71                     foreach (string text in comments)
     72                     {
     73                         if (text.Trim() != "")
     74                         {
     75                             cmm.Comments.Add(new CodeCommentStatement(text.Trim().TrimStart("///".ToCharArray()).Trim(), true));
     76                         }
     77                     }
     78 
     79 
     80 
     81                     if (cmm.Name == "InitializeComponent")
     82                     {
     83                         //region 
     84                         CodeRegionDirective codeRegion = new CodeRegionDirective(CodeRegionMode.Start, "Windows 窗体设计器生成的代码");
     85                         CodeRegionDirective codeEndRegion = new CodeRegionDirective(CodeRegionMode.End, "");
     86 
     87                         cmm.StartDirectives.Add(codeRegion);
     88                         cmm.EndDirectives.Add(codeEndRegion);
     89                     }
     90 
     91                     //MemberAttributes.Family is protected
     92                     //cmm.Attributes = MemberAttributes.Override | MemberAttributes.Family;
     93                     cmm.Attributes = GetMethodAttrMapping(method);
     94                     cmm.ReturnType = new CodeTypeReference(method.ReturnType.ToString());
     95 
     96                     foreach (var p in method.ParameterList.Parameters)
     97                     {
     98                         CodeParameterDeclarationExpression cpd = new CodeParameterDeclarationExpression();
     99                         cpd.Name = p.Identifier.ToString();
    100 
    101                         cpd.Type = new CodeTypeReference(p.Type.ToString());
    102 
    103                         cmm.Parameters.Add(cpd);
    104                     }
    105                     //包含方法{};,会重复生成{};
    106                     string codeBody = method.Body.ToString();
    107                     codeBody = codeBody.Trim().TrimStart('{').TrimEnd('}').Trim().TrimEnd(';');
    108                     if (codeBody != "")
    109                     {
    110                         CodeSnippetExpression csbody = new CodeSnippetExpression(codeBody);
    111                         CodeExpressionStatement stmt = new CodeExpressionStatement(csbody);
    112                         //Add the expression statements to the method.
    113                         cmm.Statements.Add(stmt);
    114                     }
    115                     myDesignerClass.Members.Add(cmm);
    116 
    117                 }
    118                 if (m is MemberDeclarationSyntax)
    119                 {
    120 
    121                 }
    122             }
    123 
    124             ccu.Namespaces.Add(ns);
    125 
    126             //Partial Class
    127             myDesignerClass.IsPartial = true;
    128    
    129 
    130             ns.Types.Add(myDesignerClass);
    131 
    132           
    133 
    134             return ccu;
    135         }

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

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

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

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

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

          

  • 相关阅读:
    数据类型(列类型-小数型)
    Python全栈开发之2、数据类型-数值、字符串、列表、字典、元组和文件处理
    Python全栈开发之3、深浅拷贝、变量和函数、递归、函数式编程、内置函数
    Python全栈开发之1、python基础初识介绍以及安装
    数据类型(列类型)
    中文数据问题
    SQL--数据--基本操作
    SQL--数据表--基本操作
    SQL--数据库--基本操作
    Mysql数据库
  • 原文地址:https://www.cnblogs.com/isaboy/p/DesignSurface.html
Copyright © 2020-2023  润新知