我正在尝试为InitializeComponent
自定义Windows窗体设计器的代码生成。 MSDN文章"Customizing Code Generation in the .NET Framework Visual Designers"包含一个"Controlling Code Generation"部分,其中介绍了如何完成此操作的基础知识。
我在上面的文章中密切关注了一个例子:
//using System.ComponentModel.Design.Serialization;
class SomeFormSerializer : CodeDomSerializer
{
public override object Serialize(IDesignerSerializationManager manager,
object value)
{
// first, let the default serializer do its work:
var baseSerializer = (CodeDomSerializer)manager.GetSerializer(
typeof(Form).BaseType, typeof(CodeDomSerializer));
object codeObject = baseSerializer.Serialize(manager, value);
// then, modify the generated CodeDOM -- add a comment as the 1st line:
if (codeObject is CodeStatementCollection)
{
var statements = (CodeStatementCollection)codeObject;
statements.Insert(0, new CodeCommentStatement("CODEDOM WAS HERE"));
}
// finally, return the modified CodeDOM:
return codeObject;
}
}
现在我把它连接到我的表单SomeForm
:
[DesignerSerializer(typeof(SomeFormSerializer), typeof(CodeDomSerializer))]
class SomeForm : Form { … }
然后,Forms Designer可能会生成以下InitializeComponent
代码:
private void InitializeComponent()
{
… /* (general setup code, such as a call to `this.SuspendLayout`) */
//
// someButton
//
… /* (someButton's properties are set) */
// CODEDOM WAS HERE!
//
// SomeForm
//
… /* (form's properties are set) */
… /* (general setup code, such as a call to `this.ResumeLayout`) */
}
请注意,评论// CODEDOM WAS HERE
未添加为InitializeComponent
中的第一行,而只是作为处理表单对象本身属性的代码块的第一行。
如果我希望能够修改整个方法的生成CodeDOM,而不仅仅是处理特定对象的部分,我该怎么做?
背景:为什么我要这样做?在Windows窗体中,如果在数据绑定期间需要灵活的值转换,通常必须求助于订阅
Format
和{ {1}}某个特定Parse
对象的事件。所以我正在创建一个专门的Binding
子类(让我们称之为Binding
),这简化了这个过程。现在,问题是在Windows窗体设计器中设置数据绑定时,生成的代码会创建
ConvertingBinding
的实例;但是,我希望设计者实例化我的专用子类。我当前的方法是让设计者首先创建一个CodeDOM树,然后遍历该树,并通过Binding
的实例化替换Binding
的所有实例化。
答案 0 :(得分:12)
您需要创建两个Form
类。第一个Form
,DesignerSerializerAttribute
。第二个Form
是第一个的后代。之后,您可以为第二个InitializeComponent()
及其控件或组件自定义Form
。
为此,您应使用manager.Context
获取包含StatementContext
控件序列化代码的所有CodeStatementCollection
和Form
个对象。
以下是一些简单的步骤 包括库:
using System.CodeDom;
using System.ComponentModel.Design.Serialization;
using System.Collections;
创建新表单并添加DesignerSerializerAttribute
:
[DesignerSerializer(typeof(CustomFormSerializer), typeof(CodeDomSerializer))]
class CustomForm : Form { … }
创建CustomForm
后代并向其添加一些控件或组件:
class CustomForm1 : CustomForm { … }
将方法添加到CustomFormSerializer
以处理CodeStatementCollection
,例如:
private void DoSomethingWith(CodeStatementCollection statements)
{
statements.Insert(0, new CodeCommentStatement("CODEDOM WAS HERE"));
}
在Serialize
方法中,使用周期manager.Context
:
public override object Serialize(IDesignerSerializationManager manager,
object value)
{
//Cycle through manager.Context
for (int iIndex = 0; manager.Context[iIndex] != null; iIndex++)
{
object context = manager.Context[iIndex];
if (context is StatementContext)
// Get CodeStatementCollection objects from StatementContext
{
ObjectStatementCollection objectStatementCollection =
((StatementContext)context).StatementCollection;
// Get each entry in collection.
foreach (DictionaryEntry dictionaryEntry in objectStatementCollection)
// dictionaryEntry.Key is control or component contained in CustomForm descendant class
// dictionartEntry.Value is CodeDOM for this control or component
if (dictionaryEntry.Value is CodeStatementCollection)
DoSomethingWith((CodeStatementCollection)dictionaryEntry.Value);
}
//Do something with each collection in manager.Context:
if (context is CodeStatementCollection)
DoSomethingWith((CodeStatementCollection)context);
}
// Let the default serializer do its work:
CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.
GetSerializer(value.GetType().BaseType, typeof(CodeDomSerializer));
object codeObject = baseClassSerializer.Serialize(manager, value);
// Then, modify the generated CodeDOM:
if (codeObject is CodeStatementCollection)
DoSomethingWith((CodeStatementCollection)codeObject);
// Finally, return the modified CodeDOM:
return codeObject;
}