如何自定义InitializeComponent的代码生成?更具体地说,如何对所有生成的代码进行后处理?

2024-01-12

我正在尝试自定义 Windows 窗体设计器的代码生成InitializeComponent。 MSDN 文章“在 .NET Framework 可视化设计器中自定义代码生成” http://msdn.microsoft.com/en-us/library/ms973818.aspx包含一个部分《控制代码生成》 http://msdn.microsoft.com/en-us/library/ms973818.aspx#custcodegen_topic8这解释了如何做到这一点的基础知识。

我密切关注了上面文章中的一个例子:

//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 { … }

然后,表单设计器可能会生成以下内容InitializeComponent code:

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 and Parse一些特定的事件Binding目的。所以我正在创建一个专门的Binding子类(我们称之为ConvertingBinding)这稍微简化了这个过程。

现在的问题是,当在 Windows 窗体设计器中设置数据绑定时,生成的代码会创建Binding;但是,我希望设计者实例化我的专门子类。我当前的方法是让设计者首先创建一个 CodeDOM 树,然后遍历该树并替换Binding通过实例化ConvertingBinding.


您需要创建两个Form班级。第一的Form with a DesignerSerializerAttribute。第二Form是第一个的后代。之后就可以自定义了InitializeComponent()第二个Form以及它的控件或组件。 为此你应该使用manager.Context得到所有StatementContext and CodeStatementCollection包含序列化代码的对象Form的控制。

这是一些简单的步骤。
包括库:

using System.CodeDom;
using System.ComponentModel.Design.Serialization;
using System.Collections;

创建新表单并添加DesignerSerializerAttribute:

[DesignerSerializer(typeof(CustomFormSerializer), typeof(CodeDomSerializer))]
class CustomForm : Form { … }

Create CustomForm后代并向其添加一些控件或组件:

class CustomForm1 : CustomForm { … }

将方法添加到CustomFormSerializer用于加工CodeStatementCollection, 例如:

private void DoSomethingWith(CodeStatementCollection statements)
{
    statements.Insert(0, new CodeCommentStatement("CODEDOM WAS HERE"));
}

In 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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何自定义InitializeComponent的代码生成?更具体地说,如何对所有生成的代码进行后处理? 的相关文章

随机推荐