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[];
  5. var namespaceDeclration = (NamespaceDeclarationSyntax)firstMember;
  6. var designClassDeclaration = (ClassDeclarationSyntax)namespaceDeclration.Members[];
  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. #endregion
  57.  
  58. var method = (MethodDeclarationSyntax)m;
  59.  
  60. var cmm = new CodeMemberMethod();
  61. cmm.Name = method.Identifier.ToString();
  62.  
  63. ///XML注释
  64. string[] comments = xmlTrivia.ToString().Split("\r\n".ToCharArray());
  65. foreach (string text in comments)
  66. {
  67. if (text.Trim() != "")
  68. {
  69. cmm.Comments.Add(new CodeCommentStatement(text.Trim().TrimStart("///".ToCharArray()).Trim(), true));
  70. }
  71. }
  72.  
  73. if (cmm.Name == "InitializeComponent")
  74. {
  75. //region
  76. CodeRegionDirective codeRegion = new CodeRegionDirective(CodeRegionMode.Start, "Windows 窗体设计器生成的代码");
  77. CodeRegionDirective codeEndRegion = new CodeRegionDirective(CodeRegionMode.End, "");
  78.  
  79. cmm.StartDirectives.Add(codeRegion);
  80. cmm.EndDirectives.Add(codeEndRegion);
  81. }
  82.  
  83. //MemberAttributes.Family is protected
  84. //cmm.Attributes = MemberAttributes.Override | MemberAttributes.Family;
  85. cmm.Attributes = GetMethodAttrMapping(method);
  86. cmm.ReturnType = new CodeTypeReference(method.ReturnType.ToString());
  87.  
  88. foreach (var p in method.ParameterList.Parameters)
  89. {
  90. CodeParameterDeclarationExpression cpd = new CodeParameterDeclarationExpression();
  91. cpd.Name = p.Identifier.ToString();
  92.  
  93. cpd.Type = new CodeTypeReference(p.Type.ToString());
  94.  
  95. cmm.Parameters.Add(cpd);
  96. }
  97. //包含方法{};,会重复生成{};
  98. string codeBody = method.Body.ToString();
  99. codeBody = codeBody.Trim().TrimStart('{').TrimEnd('}').Trim().TrimEnd(';');
  100. if (codeBody != "")
  101. {
  102. CodeSnippetExpression csbody = new CodeSnippetExpression(codeBody);
  103. CodeExpressionStatement stmt = new CodeExpressionStatement(csbody);
  104. //Add the expression statements to the method.
  105. cmm.Statements.Add(stmt);
  106. }
  107. myDesignerClass.Members.Add(cmm);
  108.  
  109. }
  110. if (m is MemberDeclarationSyntax)
  111. {
  112.  
  113. }
  114. }
  115.  
  116. ccu.Namespaces.Add(ns);
  117.  
  118. //Partial Class
  119. myDesignerClass.IsPartial = true;
  120.  
  121. ns.Types.Add(myDesignerClass);
  122.  
  123. return ccu;
  124. }

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

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

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

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

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

C#用DesignSurface实现一个简单的窗体设计器的更多相关文章

  1. C#如何实现一个简单的流程图设计器

    以前看过不少Window Form开发的流程图设计器,支持节点拖放,非常方便即可设计出很美观的流程图,作为一个程序员,对其内部实现原理一直很好奇,感叹有朝一日自己如果可以开发一款类似的软件那是多么让人 ...

  2. Windows 窗体设计器(Windows Forms Designer)入门

      Visual Studio 2010 更新:2010 年 9 月 Windows 窗体设计器提供多个用于生成 Windows 窗体应用程序的工具. 本演练阐释如何使用设计器提供的各种工具生成应用程 ...

  3. 解析大型.NET ERP系统核心组件 查询设计器 报表设计器 窗体设计器 工作流设计器 任务计划设计器

    企业管理软件包含一些公共的组件,这些基础的组件在每个新项目立项阶段就必须考虑.核心的稳定不变功能,方便系统开发与维护,也为系统二次开发提供了诸多便利.比如通用权限管理系统,通用附件管理,通用查询等组件 ...

  4. 通过用 .NET 生成自定义窗体设计器来定制应用程序

    通过用 .NET 生成自定义窗体设计器来定制应用程序 https://www.microsoft.com/china/MSDN/library/netFramework/netframework/Cu ...

  5. C#基础系列:开发自己的窗体设计器(PropertyGrid显示中文属性名)

    既然是一个窗体设计器,那就应该能够设置控件的属性,设置属性最好的当然是PropertyGrid了,我们仅仅需要使用一个PropertyGrid.SelectedObject = Control就可以搞 ...

  6. WinForm编程时窗体设计器中ComboBox控件大小的设置

    问题描述: 在VS中的窗体设计器中拖放一个ComboBox控件后想调整控件的大小.发现在控件上用鼠标只能拖动宽度(Width)无法拖动(Height). 解决过程: 1.控件无法拖动,就在属性窗口中设 ...

  7. C#自定义运行时窗体设计器Runtime FormDesigner

    写在前面:因为业务的需要,有时会使用到自定义运行时窗体设计器Runtime FormDesigner,实现的功能,就是IDE设计器的简化.设想一下,如果可以在程序运行时,再设计一个Form,然后编译代 ...

  8. 在.NET Core 3.0 Preview上使用Windows窗体设计器

    支持使用基于Windows窗体应用程序的.NET Core 3.0(预览)的Windows窗体设计器 介绍 截至撰写本文时,Microsoft和社区目前正在测试.NET Core 3.0.如果您在.N ...

  9. C# winFrom窗体设计问题-部分文件打不开窗体设计器 变成类.cs

    https://zhidao.baidu.com/question/1513483178103163220.html C# winform程序设计的时候,出现了问题.默认主窗体form1(改名form ...

随机推荐

  1. lPC1788的串口通讯

    #ifndef __DEBUGSERIAL_H_ #define __DEBUGSERIAL_H_ #include "sys.h" #include "stdio.h& ...

  2. HUST 1605 Gene recombination

    简单广搜.4进制对应的10进制数来表示这些状态,总共只有(4^12)种状态. #include<cstdio> #include<cstring> #include<cm ...

  3. Ural Vol1(dif>=900)

    目前已AC:  2 1040.Airline Company(构造) 题目要求与每个顶点相连的所有边编号最大公约数为1,其实只要其中的两条边编号互质,所有边编号的最大公约数一定为1.我们知道相邻的数字 ...

  4. 自然语言处理高手_相关资源_开源项目(比如:分词,word2vec等)

    (1) 中科院自动化所的博士,用神经网络做自然语言处理:http://licstar.net (2) 分词项目:https://github.com/fxsjy/jieba(3) 清华大学搞的中文分词 ...

  5. iOS中UITextField 使用全面解析 分类: ios技术 2015-04-10 14:37 153人阅读 评论(0) 收藏

    //初始化textfield并设置位置及大小   UITextField *text = [[UITextField alloc]initWithFrame:CGRectMake(20, 20, 13 ...

  6. 按住ctrl键可以在新窗口打开图片

    用firebug查看网页时,img标签(或background属性里面的url地址源)里面的图片源按住ctrl键可以弹出新窗口显示,并可右键另存为到本地目录

  7. jQuery对象插件封装步骤

    jQuery是js的一个非常优秀的库,它大大简化了js的很多操作,并且解决了js的大部分兼容性问题.甚至很多css兼容性问题,用jQuery写都能解决. 这里是对象插件的封装.当然,封装插件很多,这里 ...

  8. 一个完整的PHP类包含的七种语法说明

    类中的七种语法说明 -属性 -静态属性 -方法 -静态方法 -类常量 -构造函数 -析构函数 <?php class Student { // 类里的属性.方法和函数的访问权限有 (函数和方法是 ...

  9. leetcode[149]Max Points on a Line

    Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. ...

  10. I/O流

     转自:http://www.cnblogs.com/dolphin0520/p/3791327.html 一.什么是IO Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的 ...