简体   繁体   English

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

[英]Access Form custom attributes at design-time

I found an example of ControlDesigner that showed me how to add controls and create an event handler using IEventBindingService and then add some code in that event handler using CodeTypeDeclaration . 我找到了ControlDesigner的示例,该示例向我展示了如何使用IEventBindingService添加控件并创建事件处理程序,然后使用CodeTypeDeclaration在该事件处理程序中添加一些代码。 But when I tried to access custom attributes of a base form CodeTypeDeclaration returned an empty collection. 但是,当我尝试访问基本表单的自定义属性时, CodeTypeDeclaration返回了一个空集合。 The following example shows that CodeTypeDeclaration does not return any custom attributes of a base form: 下面的示例显示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));
        }
    }
}

I tried using custom CodeDomSerializer for my form but with this approach I can only access code in InitializeComponent method. 我尝试为表单使用自定义CodeDomSerializer ,但是使用这种方法,我只能访问InitializeComponent方法中的代码。 Is there any other way I could access custom attributes of my form? 还有其他方法可以访问表单的自定义属性吗?

The reason I want this is so I could create an action in designer to add/change parameters of my custom attribute on a form. 我想要这样做的原因是,我可以在设计器中创建一个操作,以在表单上添加/更改自定义属性的参数。

I finally found what I was looking for, accessing attributes (and imports) is possible using EnvDTE. 我终于找到了我想要的东西,使用EnvDTE可以访问属性(和导入)。 Here is my complete example that can add/change attribute value: 这是我可以添加/更改属性值的完整示例:

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;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM