您的位置:首页 > 编程语言 > C#

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

2017-11-08 09:31 681 查看
转自:http://www.cnblogs.com/isaboy/p/DesignSurface.html

  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中的控件引用







 

 但此设计器还有很多不完善的地方,后期有时间再完善吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c# 设计 winform 界面
相关文章推荐