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中的控件引用
但此设计器还有很多不完善的地方,后期有时间再完善吧。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
原文链接:http://www.cnblogs.com/isaboy/p/DesignSurface.html
dy("nrwz");
查看更多关于C#利用DesignSurface如何实现简单的窗体设计器的详细内容...