当前位置: 移动技术网 > IT编程>开发语言>c# > C#利用DesignSurface如何实现简单的窗体设计器

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

2019年07月18日  | 移动技术网IT编程  | 我要评论

system.componentmodel.design.designsurface是为设计组件提供一个用户界面,通过它可以实现一个简单的窗体设计器。

在构建之前,我们需要引入system.design.dll,否则会出现找不到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设计器

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

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

 //直接返回代码,最简单
 public string gettextcscode()
 {
 flush();
 return __cstextcode;
 }

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

 

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

总结

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网