• 技术文章 >后端开发 >C#.Net教程

    C#利用DesignSurface实现简单的窗体设计器的方法介绍(图文)

    黄舟黄舟2017-03-17 13:14:58原创3660
    这篇文章主要介绍了C#利用DesignSurface如何实现简单窗体设计器的相关资料,文中通过图文及示例代码介绍的很详细,对大家具有一定的参考价值,需要的朋友们下面来一起学习学习吧。

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

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

    总结

    以上就是C#利用DesignSurface实现简单的窗体设计器的方法介绍(图文)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:详细介绍使用C#实现Windows Form调用R进行绘图与显示的方法(图) 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • c语言怎么计算n的阶乘• c语言数组如何初始化• c语言的换行符号是什么• c语言怎么将数字转换成字符串• c语言如何进行强制类型转换
    1/1

    PHP中文网