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

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

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

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

猜你喜欢

  • 为Xamarin.Forms的导航栏增加搜索功能

    2022-01-28 18:38:58
  • Java代码实现简单酒店管理系统

    2023-11-21 03:38:57
  • C#难点逐个击破(2):out返回参数

    2022-02-02 01:24:18
  • Java语言实现快速幂取模算法详解

    2022-06-08 13:18:51
  • 详解C#使用AD(Active Directory)验证内网用户名密码

    2023-03-03 23:17:47
  • Android之PreferenceActivity应用详解

    2023-03-28 14:26:37
  • RecyclerView实现拖拽排序效果

    2022-09-14 01:23:40
  • Java编程中随机数的生成方式总结

    2022-06-14 11:57:27
  • c语言switch反汇编的实现

    2023-06-29 03:38:17
  • C#向线程中传递多个参数的解决方法(两种)

    2022-08-16 19:16:30
  • Java实现的具有GUI的校园导航系统的完整代码

    2022-06-28 03:43:56
  • Android 中 退出多个activity的经典方法

    2023-02-09 04:38:59
  • C#实现将DataTable内容输出到Excel表格的方法

    2023-05-01 15:20:38
  • 基于C语言实现静态通讯录的示例代码

    2023-07-02 22:07:38
  • Spring Cloud之服务监控turbine的示例

    2023-04-20 23:26:44
  • Java 开启多线程常见的4种方法

    2023-11-23 02:30:10
  • c#图片处理之图片裁剪成不规则图形

    2023-02-23 02:43:58
  • SpringBoot @PropertySource与@ImportResource有什么区别

    2023-08-22 02:02:47
  • C#7.0中新特性汇总

    2023-06-24 18:29:13
  • c# 实现IComparable、IComparer接口、Comparer类的详解

    2022-07-23 00:25:56
  • asp之家 软件编程 m.aspxhome.com