软件编程
位置:首页>> 软件编程>> C#编程>> C#利用DesignSurface如何实现简单的窗体设计器

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

作者:JackWang-CUMT  发布时间:2023-10-18 18:43:28 

标签:c#,designsurface,窗体设计器

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

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

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


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设计器

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

但是该设计器并不能实现控件拖放和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()方法。

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

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

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


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

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

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

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

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

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

来源:http://www.cnblogs.com/isaboy/p/DesignSurface.html

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com