首页 > 编程 > C# > 正文

C#利用DesignSurface如何实现简单的窗体设计器

2019-10-29 21:13:10
字体:
来源:转载
供稿:网友

code>System.ComponentModel.Design.DesignSurface是为设计组件提供一个用户界面,通过它可以实现一个简单的窗体设计器。

在构建之前,我们需要引入System.Design.dll,否则会出现找不到DesignSurface的错误。

designsurface,c,开发窗体设计器,窗体设计

private void Form1_Load(object sender, EventArgs e) {  //引用System.Deisgn.dll  DesignSurface ds = new DesignSurface();  //开始加载窗体  ds.BeginLoad(typeof(Form));  Control designerContorl = (Control)ds.View;  designerContorl.Dock = DockStyle.Fill;  this.Controls.Add(designerContorl); }

运行后出现简单的一个UI设计器

designsurface,c,开发窗体设计器,窗体设计

但是该设计器并不能实现控件拖放和UI设计器,以及控件的属性配置。

为了支持从源代码加载初始化窗体,需要对源码中的相关方法进行解析,这里我们 CodeDomDesignerLoader来实现定制化业务,CodeDomDesignerLoader是提供用于实现基于 CodeDOM 的设计器加载程序的基类。

继承它的类需要重写CodeCompileUnit Parse()方法,来实现加载窗体:

protected override CodeCompileUnit Parse() {    #region 源文件读取  var sw = new StreamReader(@"E:/FrmUser.cs");  var sw_designer = new StreamReader(@"E:/FrmUser.Designer.cs");  string formCodeCS = sw.ReadToEnd();  string formCodeDesigner = sw_designer.ReadToEnd();  List<string> source = new List<string>();  source.Add(formCodeCS);  source.Add(formCodeDesigner);  #endregion  //Rolsyn解析C#  var rootDesigner = Source2CodeDom.Parse(formCodeDesigner);  codeDesingerCompileUnit = Source2CodeDom.GetDesignerCodeComplieUnit(rootDesigner);  var rootCS = Source2CodeDom.Parse(formCodeCS);  codeCSCompileUnit = Source2CodeDom.GetCodeComplieUnit(rootCS);  //MergeFormSource  string mergeS = Source2CodeDom.MergeFormSource(formCodeDesigner, formCodeCS);  codeMergeCompileUnit = Source2CodeDom.GetMergeDesignerCodeComplieUnit(mergeS);  return codeMergeCompileUnit;

解析的方法如下,但是此解析只是用于代码的生成,并不能用户UI界面的显示:

public static CodeCompileUnit GetDesignerCodeComplieUnit2(CompilationUnitSyntax root) {  CodeCompileUnit ccu = new CodeCompileUnit();  var firstMember = root.Members[0];  var namespaceDeclration = (NamespaceDeclarationSyntax)firstMember;  var designClassDeclaration = (ClassDeclarationSyntax)namespaceDeclration.Members[0];  var myDesignerClass = new CodeTypeDeclaration(designClassDeclaration.Identifier.ToString());  var initializeComponent = new CodeMemberMethod();  var ns = new CodeNamespace(namespaceDeclration.Name.ToString());  foreach (var m in designClassDeclaration.Members)  {  if (m is ConstructorDeclarationSyntax)  {   var ctor = ((ConstructorDeclarationSyntax)m);   var codeBody = ctor.Body.ToString();   codeBody = codeBody.Trim().TrimStart('{').TrimEnd('}').Trim().TrimEnd(';');   CodeSnippetExpression csbody = new CodeSnippetExpression(codeBody);   CodeExpressionStatement stmt = new CodeExpressionStatement(csbody);   //Add the expression statements to the method.   // InitializeComponent   var cctor = new CodeConstructor();   cctor.Name = ctor.Identifier.ToString();   //var cmm = new CodeMemberMethod();   //cmm.Name = ctor.Identifier.ToString();   //cmm.Attributes = GetCtoRAttrMapping(ctor);   //cmm.ReturnType = new CodeTypeReference(typeof(void));   cctor.Statements.Add(stmt);   myDesignerClass.Members.Add(cctor);  }  if (m is FieldDeclarationSyntax)  {   var F = ((FieldDeclarationSyntax)m);   var type = F.Declaration.Type;   foreach (var variable in F.Declaration.Variables)   {   var field = new CodeMemberField();   field.Name = variable.Identifier.ToString();   field.Type = new CodeTypeReference(type.ToString());   field.Attributes = GetFieldAttrMapping(F);   //field.InitExpression = new CodePrimitiveExpression(null);   myDesignerClass.Members.Add(field);   }  }  if (m is MethodDeclarationSyntax)  {   var node = m as MethodDeclarationSyntax;   #region xml comments   var xmlTrivia = node.GetLeadingTrivia()   .Select(i => i.GetStructure())   .OfType<DocumentationCommentTriviaSyntax>()   .FirstOrDefault();    #endregion   var method = (MethodDeclarationSyntax)m;   var cmm = new CodeMemberMethod();   cmm.Name = method.Identifier.ToString();   ///XML注释   string[] comments = xmlTrivia.ToString().Split("/r/n".ToCharArray());   foreach (string text in comments)   {   if (text.Trim() != "")   {    cmm.Comments.Add(new CodeCommentStatement(text.Trim().TrimStart("///".ToCharArray()).Trim(), true));   }   }   if (cmm.Name == "InitializeComponent")   {   //region    CodeRegionDirective codeRegion = new CodeRegionDirective(CodeRegionMode.Start, "Windows 窗体设计器生成的代码");   CodeRegionDirective codeEndRegion = new CodeRegionDirective(CodeRegionMode.End, "");   cmm.StartDirectives.Add(codeRegion);   cmm.EndDirectives.Add(codeEndRegion);   }   //MemberAttributes.Family is protected   //cmm.Attributes = MemberAttributes.Override | MemberAttributes.Family;   cmm.Attributes = GetMethodAttrMapping(method);   cmm.ReturnType = new CodeTypeReference(method.ReturnType.ToString());   foreach (var p in method.ParameterList.Parameters)   {   CodeParameterDeclarationExpression cpd = new CodeParameterDeclarationExpression();   cpd.Name = p.Identifier.ToString();   cpd.Type = new CodeTypeReference(p.Type.ToString());   cmm.Parameters.Add(cpd);   }   //包含方法{};,会重复生成{};   string codeBody = method.Body.ToString();   codeBody = codeBody.Trim().TrimStart('{').TrimEnd('}').Trim().TrimEnd(';');   if (codeBody != "")   {   CodeSnippetExpression csbody = new CodeSnippetExpression(codeBody);   CodeExpressionStatement stmt = new CodeExpressionStatement(csbody);   //Add the expression statements to the method.   cmm.Statements.Add(stmt);   }   myDesignerClass.Members.Add(cmm);  }  if (m is MemberDeclarationSyntax)  {  }  }  ccu.Namespaces.Add(ns);  //Partial Class  myDesignerClass.IsPartial = true;   ns.Types.Add(myDesignerClass);    return ccu; }

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

designsurface,c,开发窗体设计器,窗体设计

designsurface,c,开发窗体设计器,窗体设计

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

 //直接返回代码,最简单 public string GetTextCSCode() { Flush(); return __CSTextCode; }

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

designsurface,c,开发窗体设计器,窗体设计

designsurface,c,开发窗体设计器,窗体设计

 designsurface,c,开发窗体设计器,窗体设计

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

 

注:相关教程知识阅读请移步到c#教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表