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

时间:2015-12-14 08:39:41

标签: c# winforms custom-attributes design-time

我找到了一个ControlDesigner示例,它向我展示了如何使用IEventBindingService添加控件并创建事件处理程序,然后使用CodeTypeDeclaration在该事件处理程序中添加一些代码。但是当我尝试访问基本表单的自定义属性时CodeTypeDeclaration返回一个空集合。以下示例显示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));
        }
    }
}

我尝试将自定义CodeDomSerializer用于我的表单但是使用此方法我只能使用InitializeComponent方法访问代码。有没有其他方法可以访问我的表单的自定义属性?

我想要这个的原因是我可以在设计器中创建一个动作来在表单上添加/更改我的自定义属性的参数。

1 个答案:

答案 0 :(得分:0)

我终于找到了我要找的东西,使用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;
        }
    }
}