C# 在设计时访问表单自定义属性

C# 在设计时访问表单自定义属性,c#,winforms,custom-attributes,design-time,C#,Winforms,Custom Attributes,Design Time,我找到了ControlDesigner的一个示例,它向我展示了如何使用IEventBindingService添加控件和创建事件处理程序,然后使用CodeTypeDeclaration在该事件处理程序中添加一些代码。但是当我试图访问基本表单的自定义属性时,codetypedesclaration返回了一个空集合。以下示例显示CodeTypeDeclaration不返回基本表单的任何自定义属性: using System; using System.CodeDom; using System.Co

我找到了ControlDesigner的一个示例,它向我展示了如何使用
IEventBindingService
添加控件和创建事件处理程序,然后使用
CodeTypeDeclaration
在该事件处理程序中添加一些代码。但是当我试图访问基本表单的自定义属性时,
codetypedesclaration
返回了一个空集合。以下示例显示
CodeTypeDeclaration
不返回基本表单的任何自定义属性:

using System;
using System.CodeDom;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace WindowsFormsApplication1
{
    [MyCustom("new sample text")]
    public class MyForm : MyBaseForm
    {
        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // MyForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.ClientSize = new System.Drawing.Size(617, 450);
            this.ResumeLayout(false);
        }

        #endregion

        public MyForm()
        {
            InitializeComponent();
        }
    }

    [MyCustom("sample text")]
    [Designer(typeof(MyBaseFormDesigner), typeof(IRootDesigner))]
    public partial class MyBaseForm : Form
    {
        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // MyBaseForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(391, 337);
            this.ResumeLayout(false);

        }

        #endregion

        public MyBaseForm()
        {
            InitializeComponent();
        }
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public class MyCustomAttribute : Attribute
    {
        public string Text { get; set; }

        public MyCustomAttribute(string text)
        {
            this.Text = text;
        }
    }

    public class MyBaseFormDesigner : DocumentDesigner
    {
        public override void Initialize(IComponent component)
        {
            base.Initialize(component);
            Verbs.Add(new DesignerVerb("Show CodeTypeDeclaration", OnShowCodeTypeDeclaration));
        }

        private static string GetCode(CodeTypeDeclaration codeType)
        {
            var code = new System.Text.StringBuilder();
            using (var provider = new Microsoft.CSharp.CSharpCodeProvider()) {
                using (var writer = new System.IO.StringWriter(code)) {
                    provider.GenerateCodeFromType(codeType, writer, new System.CodeDom.Compiler.CodeGeneratorOptions());
                }
            }
            return code.ToString();
        }

        protected virtual void OnShowCodeTypeDeclaration(object sender, EventArgs args)
        {
            var codeType = GetService(typeof(CodeTypeDeclaration)) as CodeTypeDeclaration;
            if (MessageBox.Show("Add MyCustomAttribute?", "", MessageBoxButtons.YesNo) == DialogResult.Yes) {
                codeType.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(MyCustomAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression("sample text from designer"))));
            }
            MessageBox.Show(GetCode(codeType));
        }
    }
}
使用系统;
使用System.CodeDom;
使用系统组件模型;
使用System.ComponentModel.Design;
使用System.Windows.Forms;
使用System.Windows.Forms.Design;
命名空间Windows窗体应用程序1
{
[MyCustom(“新示例文本”)]
公共类MyForm:MyBaseForm
{
#区域Windows窗体设计器生成的代码
/// 
///设计器支持所需的方法-不修改
///此方法的内容与代码编辑器一起使用。
/// 
私有void InitializeComponent()
{
这个.SuspendLayout();
// 
//MyForm
// 
此.AutoScaleDimensions=新系统.Drawing.SizeF(6F,13F);
this.ClientSize=新系统图纸尺寸(617450);
此选项为.resume布局(false);
}
#端区
公共MyForm()
{
初始化组件();
}
}
[MyCustom(“示例文本”)]
[Designer(typeof(MyBaseFormDesigner)、typeof(IRootDesigner))]
公共部分类MyBaseForm:Form
{
#区域Windows窗体设计器生成的代码
/// 
///设计器支持所需的方法-不修改
///此方法的内容与代码编辑器一起使用。
/// 
私有void InitializeComponent()
{
这个.SuspendLayout();
// 
//MyBaseForm
// 
此.AutoScaleDimensions=新系统.Drawing.SizeF(6F,13F);
this.AutoScaleMode=System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize=新系统.Drawing.Size(391337);
此选项为.resume布局(false);
}
#端区
公共MyBaseForm()
{
初始化组件();
}
}
[AttributeUsage(AttributeTargets.Class,AllowMultiple=true,Inherited=true)]
公共类MyCustomAttribute:属性
{
公共字符串文本{get;set;}
公共MyCustomAttribute(字符串文本)
{
this.Text=文本;
}
}
公共类MyBaseFormDesigner:DocumentDesigner
{
公共覆盖无效初始化(IComponent组件)
{
初始化(组件);
添加(新的DesignerB(“ShowCodeTypeDeclaration”,OnShowCodeTypeDeclaration));
}
私有静态字符串GetCode(CodeTypeDeclaration codeType)
{
var code=new System.Text.StringBuilder();
使用(var provider=new Microsoft.CSharp.CSharpCodeProvider()){
使用(var writer=new System.IO.StringWriter(代码)){
provider.GenerateCodeFromType(codeType、writer、new System.CodeDom.Compiler.CodeGeneratorOptions());
}
}
返回代码.ToString();
}
ShowCodeTypeDeclaration上受保护的虚拟无效(对象发送方、事件args args)
{
var codeType=GetService(typeof(CodeTypeDeclaration))作为CodeTypeDeclaration;
if(MessageBox.Show(“添加MyCustomAttribute?”,“”,MessageBoxButtons.YesNo)=DialogResult.Yes){
添加(新的CodeAttributeDeclaration(新的CodeTypeReference(typeof(MyCustomAttribute)),新的CodeAttributeArgument(新的CodePrimitiveExpression(“来自设计器的示例文本”))));
}
Show(GetCode(codeType));
}
}
}
我尝试在表单中使用自定义
CodeDomSerializer
,但使用这种方法,我只能访问
InitializeComponent
方法中的代码。是否有其他方法可以访问表单的自定义属性


我之所以希望这样做,是因为我可以在designer中创建一个操作,在表单上添加/更改自定义属性的参数。

我终于找到了我要查找的内容,使用EnvDTE可以访问属性(和导入)。下面是我可以添加/更改属性值的完整示例:

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace WindowsFormsApplication1
{
    [MyCustom("new sample text")]
    public class MyForm : MyBaseForm
    {
        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // MyForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.ClientSize = new System.Drawing.Size(617, 450);
            this.ResumeLayout(false);
        }

        #endregion

        public MyForm()
        {
            InitializeComponent();
        }
    }

    [MyCustom("sample text")]
    [Designer(typeof(MyBaseFormDesigner), typeof(IRootDesigner))]
    public partial class MyBaseForm : Form
    {
        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // MyBaseForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(391, 337);
            this.ResumeLayout(false);

        }

        #endregion

        public MyBaseForm()
        {
            InitializeComponent();
        }
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public class MyCustomAttribute : Attribute
    {
        public string Text { get; set; }

        public MyCustomAttribute(string text = "")
        {
            this.Text = text;
        }
    }

    public class MyBaseFormDesigner : DocumentDesigner
    {
        public override void Initialize(IComponent component)
        {
            base.Initialize(component);
            Verbs.Add(new DesignerVerb("Edit MyCustomAttribute text", OnEditText));            
        }

        protected virtual void OnEditText(object sender, EventArgs args)
        {
            EnvDTE._DTE dte = GetService(typeof(EnvDTE._DTE)) as EnvDTE._DTE;
            EnvDTE80.CodeClass2 codeClass = GetCodeClass(dte.ActiveDocument.ProjectItem.FileCodeModel.CodeElements, "MyForm");
            EnvDTE80.CodeAttribute2 codeAttribute = GetCodeAttribute(codeClass, "MyCustom");
            if (codeAttribute != null) {
                string newValue = Microsoft.VisualBasic.Interaction.InputBox("Current Text", "Edit MyCustomAttribute text", RemoveQuote(codeAttribute.Value), -1, -1);
                codeAttribute.Value = (!string.IsNullOrWhiteSpace(newValue) ? "\"" + newValue + "\"" : "");
            }
        }

        private static string RemoveQuote(string str)
        {
            return !string.IsNullOrEmpty(str) && str[0] == '"' && str[str.Length - 1] == '"' ? str.Substring(1, str.Length - 2) : str;
        }

        private static EnvDTE80.CodeClass2 GetCodeClass(EnvDTE.CodeElements codeElements, string className)
        {
            if (codeElements != null) {
                foreach (EnvDTE.CodeElement item in codeElements) {
                    if (item.Kind == EnvDTE.vsCMElement.vsCMElementClass) {
                        EnvDTE80.CodeClass2 codeClass = item as EnvDTE80.CodeClass2;
                        if (codeClass != null && codeClass.Name == className) return codeClass;
                    } else if (item.Kind == EnvDTE.vsCMElement.vsCMElementNamespace) {
                        EnvDTE80.CodeClass2 codeClass = GetCodeClass(((EnvDTE.CodeNamespace)item).Members, className);
                        if (codeClass != null && codeClass.Name == className) return codeClass;
                    }

                }
            }
            return null;
        }

        private static EnvDTE80.CodeAttribute2 GetCodeAttribute(EnvDTE80.CodeClass2 codeClass, string attributeName)
        {
            if (codeClass != null) {
                foreach (EnvDTE80.CodeAttribute2 attr in codeClass.Attributes) {
                    if (attr.Name == attributeName) return attr;
                }
                return codeClass.AddAttribute(attributeName, "") as EnvDTE80.CodeAttribute2;
            }
            return null;
        }
    }
}
使用系统;
使用系统组件模型;
使用System.ComponentModel.Design;
使用System.Windows.Forms;
使用System.Windows.Forms.Design;
命名空间Windows窗体应用程序1
{
[MyCustom(“新示例文本”)]
公共类MyForm:MyBaseForm
{
#区域Windows窗体设计器生成的代码
/// 
///设计器支持所需的方法-不修改
///此方法的内容与代码编辑器一起使用。
/// 
私有void InitializeComponent()
{
这个.SuspendLayout();
// 
//MyForm
// 
此.AutoScaleDimensions=新系统.Drawing.SizeF(6F,13F);
this.ClientSize=新系统图纸尺寸(617450);
此选项为.resume布局(false);
}
#端区
公共MyForm()
{
初始化组件();
}
}
[MyCustom(“示例文本”)]
[Designer(typeof(MyBaseFormDesigner)、typeof(IRootDesigner))]
公共部分类MyBaseForm:Form
{
#区域Windows窗体设计器生成的代码
/// 
///设计器支持所需的方法-不修改
///此方法的内容与代码编辑器一起使用。
/// 
私有void InitializeComponent()
{
这个.SuspendLayout();
// 
//MyBaseForm
// 
此.AutoScaleDimensions=新系统.Drawing.SizeF(6F,13F);
this.AutoScaleMode=System.Window