2015-12-14 5 views
1

Я нашел пример ControlDesigner, который показал мне, как добавить элементы управления и создать обработчик событий с помощью IEventBindingService, а затем добавить код в обработчик этого события, используя CodeTypeDeclaration. Но когда я попытался получить доступ к пользовательским атрибутам базовой формы, CodeTypeDeclaration вернул пустую коллекцию. Следующий пример показывает, что CodeTypeDeclaration не возвращает пользовательские атрибуты базовой формы:Пользовательские атрибуты Access Form во время разработки

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 методе. Есть ли другой способ доступа к пользовательским атрибутам моей формы?

Причина, по которой я хочу, чтобы я мог создать действие в конструкторе, чтобы добавить/изменить параметры моего пользовательского атрибута в форме.

ответ

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; 
     } 
    } 
} 
Смежные вопросы