这篇文章主要介绍了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如何实现简单的窗体设计器
基础教程推荐
- 一个读写csv文件的C#类 2022-11-06
- ZooKeeper的安装及部署教程 2023-01-22
- C#控制台实现飞行棋小游戏 2023-04-22
- C# List实现行转列的通用方案 2022-11-02
- C#类和结构详解 2023-05-30
- C# windows语音识别与朗读实例 2023-04-27
- winform把Office转成PDF文件 2023-06-14
- unity实现动态排行榜 2023-04-27
- linux – 如何在Debian Jessie中安装dotnet core sdk 2023-09-26
- C# 调用WebService的方法 2023-03-09