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("\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 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中的控件引用
但此设计器还有很多不完善的地方,后期有时间再完善吧。
————————————————
版权声明:本文为CSDN博主「tmchongye」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tmchongye/article/details/63981641