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[];
var namespaceDeclration = (NamespaceDeclarationSyntax)firstMember;
var designClassDeclaration = (ClassDeclarationSyntax)namespaceDeclration.Members[];
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实现一个简单的窗体设计器的更多相关文章
- C#如何实现一个简单的流程图设计器
以前看过不少Window Form开发的流程图设计器,支持节点拖放,非常方便即可设计出很美观的流程图,作为一个程序员,对其内部实现原理一直很好奇,感叹有朝一日自己如果可以开发一款类似的软件那是多么让人 ...
- Windows 窗体设计器(Windows Forms Designer)入门
Visual Studio 2010 更新:2010 年 9 月 Windows 窗体设计器提供多个用于生成 Windows 窗体应用程序的工具. 本演练阐释如何使用设计器提供的各种工具生成应用程 ...
- 解析大型.NET ERP系统核心组件 查询设计器 报表设计器 窗体设计器 工作流设计器 任务计划设计器
企业管理软件包含一些公共的组件,这些基础的组件在每个新项目立项阶段就必须考虑.核心的稳定不变功能,方便系统开发与维护,也为系统二次开发提供了诸多便利.比如通用权限管理系统,通用附件管理,通用查询等组件 ...
- 通过用 .NET 生成自定义窗体设计器来定制应用程序
通过用 .NET 生成自定义窗体设计器来定制应用程序 https://www.microsoft.com/china/MSDN/library/netFramework/netframework/Cu ...
- C#基础系列:开发自己的窗体设计器(PropertyGrid显示中文属性名)
既然是一个窗体设计器,那就应该能够设置控件的属性,设置属性最好的当然是PropertyGrid了,我们仅仅需要使用一个PropertyGrid.SelectedObject = Control就可以搞 ...
- WinForm编程时窗体设计器中ComboBox控件大小的设置
问题描述: 在VS中的窗体设计器中拖放一个ComboBox控件后想调整控件的大小.发现在控件上用鼠标只能拖动宽度(Width)无法拖动(Height). 解决过程: 1.控件无法拖动,就在属性窗口中设 ...
- C#自定义运行时窗体设计器Runtime FormDesigner
写在前面:因为业务的需要,有时会使用到自定义运行时窗体设计器Runtime FormDesigner,实现的功能,就是IDE设计器的简化.设想一下,如果可以在程序运行时,再设计一个Form,然后编译代 ...
- 在.NET Core 3.0 Preview上使用Windows窗体设计器
支持使用基于Windows窗体应用程序的.NET Core 3.0(预览)的Windows窗体设计器 介绍 截至撰写本文时,Microsoft和社区目前正在测试.NET Core 3.0.如果您在.N ...
- C# winFrom窗体设计问题-部分文件打不开窗体设计器 变成类.cs
https://zhidao.baidu.com/question/1513483178103163220.html C# winform程序设计的时候,出现了问题.默认主窗体form1(改名form ...
随机推荐
- 百度api集合!
百度 api集市免费接口 IP地址查询 http://apistore.baidu.com/apiworks/servicedetail/114.html 频道新闻API_易源 http://apis ...
- 51驱动LCD12864
LCD12864与LCD1602最大的区别在于LCD12864可以显示汉字,同时也可以拿来画图;当然,作为图形显示不推荐lcd12864,推荐NOKIA5110 12864引脚基本和1602的引脚吻合 ...
- camstar --飞达上料
业务场景:某工厂的SMT车间接到生产PCB(3151502),数量1000片.如果实现飞达进行上料,并在贴片机工作时,系统自动进行物料消耗.3151502的BOM为1107790,1107792,11 ...
- 英文版Ubuntu安装配置搜狗拼音输入法
下载搜狗输入法 1 进入搜狗输入法官网,进入上面导航兰的 "输入法Linux版" 2 根据你安装的ubuntu是32位还是64位下载 END ubuntu安装搜狗输入法 1 进 ...
- css中的单位
一.相对长度单位: 相对长度是根据与其他事物的关系来度量的.共有3种相对长度单位:em,ex,px. 1个“em”定义为一种给定字体的font-size的值,例如,一个元素的font-size为14像 ...
- ceentos5.5 配置samba服务&用户&组
准备 Change Root Password passwd root 在提示下建立新密码 静态IP vi /etc/sysconfig/network-scripts/ifcfg-eth0 #网络 ...
- php 特别的函数
call_user_func函数和call_user_func_array函数 set_include_path
- Vim 第一天
记得第一次接触vi编辑器,好像是在海尔的机房吧,那是时候还是没有毕业的小菜鸟一只(PS:现在也是菜鸟),记得是测试一个云存储的产品.看着他们用vi编辑器,当时也没有感觉有什么(现在也没感觉……),只是 ...
- iOS 之 CALayer与UIView的区别
最大区别:CALayer (图层)不会直接渲染到屏幕上. UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它.它本身完全是由CoreAnimation来实现的. 真正的绘图部分,是由一 ...
- m3u8的浏览器播放器
前几天花了点时间研究了下怎么在浏览器中播放m3u8的视频地址,最后终于找到了两个开源的东西可以正常播放,稍稍整理下方便后来人. m3u8是什么就不介绍了,现在所有视频网站基本都是通过m3u8的方式来播 ...