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