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#教程
下一篇:C#基础入门之算法:交换
本文标题:C#利用DesignSurface如何实现简单的窗体设计器
本文地址:https://www.xiuzhanwang.com/a1/C_jiaocheng/5868.html
您可能感兴趣的文章
- 01-10Extjs4如何处理后台json数据中日期和时间
- 01-10asp.net中XML如何做增删改查操作
- 01-10C#利用反射技术实现去掉按钮选中时的边框效果
- 01-10C#图片处理3种高级应用
- 01-10C#.NET中如何批量插入大量数据到数据库中
- 01-10C#异步下载文件
- 01-10C# Console利用mspaint打开图像并保存的方法
- 01-10C#利用delegate实现Javascript的each方法
- 01-10解析C#中的常量及如何在C#编程中定义常量
- 01-10如何使用C#从word文档中提取图片
阅读排行
本栏相关
- 01-10C#通过反射获取当前工程中所有窗体并
- 01-10关于ASP网页无法打开的解决方案
- 01-10WinForm限制窗体不能移到屏幕外的方法
- 01-10WinForm绘制圆角的方法
- 01-10C#实现txt定位指定行完整实例
- 01-10WinForm实现仿视频播放器左下角滚动新
- 01-10C#停止线程的方法
- 01-10C#实现清空回收站的方法
- 01-10C#通过重写Panel改变边框颜色与宽度的
- 01-10C#实现读取注册表监控当前操作系统已
随机阅读
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文
- 01-10delphi制作wav文件的方法
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 04-02jquery与jsp,用jquery
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 01-10C#中split用法实例总结
- 01-10SublimeText编译C开发环境设置
- 01-11ajax实现页面的局部加载