博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#用DesignSurface实现一个简单的窗体设计器
阅读量:5059 次
发布时间:2019-06-12

本文共 8438 字,大约阅读时间需要 28 分钟。

  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
source = new List
();12 source.Add(formCodeCS);13 source.Add(formCodeDesigner);14 15 #endregion16 //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 //MergeFormSource22 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
() 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("\r\n".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 Class127 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中的控件引用

 

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

 

 

      

转载于:https://www.cnblogs.com/isaboy/p/DesignSurface.html

你可能感兴趣的文章
简单的贪吃蛇的另一种做法
查看>>
JAR打包和运行
查看>>
HTML5 基础知识(四)
查看>>
Java学习笔记之Scanner报错java.util.NoSuchElementException
查看>>
【排序】合并排序(2路归并)
查看>>
C#开机自动启动程序代码
查看>>
P2P平台的"我要借款"功能,是否需要上传借款人的相关资料
查看>>
大学生活--第5篇--物以类聚,人以群分
查看>>
网站运营的4点经验
查看>>
使用Pyramid搭建Web Server入门介绍
查看>>
剑指offer | 最小的K个数
查看>>
C++ | RAII 机制
查看>>
html5学习笔记(html5的基本构成)
查看>>
Codeforces 862C 异或!
查看>>
sscanf的应用
查看>>
第二篇 Python初识别及变量名定义规范
查看>>
springMVC全局Exception异常处理SimpleMappingExceptionResolver
查看>>
Apollo 1 融合 Spring 的三个入口
查看>>
ASP.NET MVC搭建项目后台UI框架—3、面板折叠和展开
查看>>
2015 Multi-University Training Contest 5
查看>>