2013-10-21 63 views
0

我有一個問題給你。我想在運行時在我的數據類中設置一些屬性的category屬性。我的數據類是自動生成的,我無法在設計時生成期間設置類別。設置屬性在運行時屬性的類別

我已經在運行時使用以下設置屬性的類別,不幸的是,當我設置第二個參數的category屬性也改變了第一個參數的類別....我缺少什麼?

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Reflection; 
using System.Diagnostics; 

namespace myApplication 
{ 
    public partial class Form1 : Form 
    { 
    /// <summary> 
    /// Required designer variable. 
    /// </summary> 
    private System.ComponentModel.IContainer components = null; 

    /// <summary> 
    /// Clean up any resources being used. 
    /// </summary> 
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
    protected override void Dispose(bool disposing) 
    { 
     if (disposing && (components != null)) 
     { 
     components.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 

    #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.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); 
     this.SuspendLayout(); 
     // 
     // propertyGrid1 
     // 
     this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill; 
     this.propertyGrid1.Location = new System.Drawing.Point(0, 0); 
     this.propertyGrid1.Name = "propertyGrid1"; 
     this.propertyGrid1.Size = new System.Drawing.Size(284, 262); 
     this.propertyGrid1.TabIndex = 0; 
     // 
     // Form1 
     // 
     this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
     this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
     this.ClientSize = new System.Drawing.Size(284, 262); 
     this.Controls.Add(this.propertyGrid1); 
     this.Name = "Form1"; 
     this.Text = "Form1"; 
     this.Load += new System.EventHandler(this.Form1_Load); 
     this.ResumeLayout(false); 

    } 

    #endregion 

    private System.Windows.Forms.PropertyGrid propertyGrid1; 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     Object selectedObject = new Shape() 
     { 
      x = 100, 
      y = 200 
     }; 

     var x = TypeDescriptor.GetProperties(selectedObject)["x"].Attributes; 
     CategoryAttribute attrx = (CategoryAttribute)x[typeof(CategoryAttribute)] as CategoryAttribute; 

     FieldInfo category_x = attrx.GetType().GetField("categoryValue", BindingFlags.NonPublic | BindingFlags.Instance); 
     if (category_x != null) 
     { 
     if (category_x.FieldType == "string".GetType()) 
     { 
      category_x.SetValue(TypeDescriptor.GetProperties(selectedObject)["x"].Attributes[typeof(CategoryAttribute)], "A_Category_For_x"); 
     } 
     } 

     Debug.Assert(attrx.Category == "A_Category_For_x"); 

     var y = TypeDescriptor.GetProperties(selectedObject)["y"].Attributes; 
     CategoryAttribute attry = (CategoryAttribute)y[typeof(CategoryAttribute)] as CategoryAttribute; 

     FieldInfo category_y = attry.GetType().GetField("categoryValue", BindingFlags.NonPublic | BindingFlags.Instance); 
     if (category_y != null) 
     { 
     if (category_y.FieldType == "string".GetType()) 
     { 
      category_y.SetValue(TypeDescriptor.GetProperties(selectedObject)["y"].Attributes[typeof(CategoryAttribute)], "A_Category_For_y"); 
     } 
     } 

     Debug.Assert(attrx.Category == "A_Category_For_x"); // here is stops... why is category for x changed???? 
     Debug.Assert(attry.Category == "A_Category_For_y"); 



     propertyGrid1.SelectedObject = selectedObject; 
     // Force the PropertyGrid to redraw itself 
     propertyGrid1.Refresh(); 
    } 

    } 

    public partial class Shape : System.ComponentModel.INotifyPropertyChanged 
    { 
    private short yField; 
    private short xField; 

    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public short y 
    { 
     get 
     { 
     return this.yField; 
     } 
     set 
     { 
     if ((this.yField != null)) 
     { 
      if ((yField.Equals(value) != true)) 
      { 
      this.yField = value; 
      this.OnPropertyChanged("y"); 
      } 
     } 
     else 
     { 
      this.yField = value; 
      this.OnPropertyChanged("y"); 
     } 
     } 
    } 


    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public short x 
    { 
     get 
     { 
     return this.xField; 
     } 
     set 
     { 
     if ((this.xField != null)) 
     { 
      if ((xField.Equals(value) != true)) 
      { 
      this.xField = value; 
      this.OnPropertyChanged("x"); 
      } 
     } 
     else 
     { 
      this.xField = value; 
      this.OnPropertyChanged("x"); 
     } 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    void OnPropertyChanged(string propertyName) 
    { 
     System.ComponentModel.PropertyChangedEventHandler handler = this.PropertyChanged; 
     if ((handler != null)) 
     { 
     handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); 
     } 
    } 
    } 
    static class Program 
    { 
    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 
     Application.Run(new Form1()); 
    } 
    } 
} 

更新/額外信息 我認爲.NET先後爲的CategoryAttribute相同的實例時,它沒有明確設置。如果我設置它,我可以改變每個屬性的類別,如下所示:

using System.ComponentModel; 
    using System.Diagnostics; 
    using System.Reflection; 
    using System; 
    using System.Linq; 

    namespace CSharpConsoleApplication 
    { 
     public static class Program 
     { 
     public static void Main() 
     { 
      Object selectedObject = new myDataClass 
      { 
      x = 100, 
      y = 200 
      }; 

      CategoryAttribute attrx = 
      selectedObject.GetType().GetProperty("x").GetCustomAttributes(typeof(CategoryAttribute), false).Single() as 
      CategoryAttribute; 

      FieldInfo category_x = attrx.GetType().GetField("categoryValue", BindingFlags.NonPublic | BindingFlags.Instance); 
      if (category_x != null) 
      { 
      if (category_x.FieldType == "string".GetType()) 
      { 
       category_x.SetValue(attrx, "categoryX"); 
      } 
      } 

      Debug.Assert(attrx.Category == "categoryX"); 

      CategoryAttribute attry = 
      selectedObject.GetType().GetProperty("y").GetCustomAttributes(typeof(CategoryAttribute), false).Single() as 
      CategoryAttribute; 

      FieldInfo category_y = attry.GetType().GetField("categoryValue", BindingFlags.NonPublic | BindingFlags.Instance); 
      if (category_y != null) 
      { 
      if (category_y.FieldType == "string".GetType()) 
      { 
       category_y.SetValue(attry, "categoryY"); 
      } 
      } 

      Debug.Assert(attrx.Category == "categoryX"); //success now! 
      Debug.Assert(attry.Category == "categoryY"); 
     } 

     public partial class myDataClass 
     { 
      [CategoryAttribute("Test")] 
      public int x { get; set; } 

      [CategoryAttribute("Default")] 
      public int y { get; set; } 
     } 
     } 
    } 

正如你所看到的,這是成功的!不幸的是,我的部分類myDataClass是自動生成的,我必須在每次生成後手動設置CategoryAttribute。我不想這樣做,但將其設置在運行時...

可能是這個額外的信息可以幫助?

回答

0

我已經解決了這個問題!使用這個前面回答:How to add property-level Attribute to the TypeDescriptor at runtime?

我創建了2類

  • PropertyOverridingTypeDescriptor.cs
  • TypeDescriptorOverridingProvider.cs

,並放置在我的更新方法下面的代碼片段(如有人說int他回答你可以看到上面的鏈接):

// prepare our property overriding type descriptor 
PropertyOverridingTypeDescriptor ctd = new PropertyOverridingTypeDescriptor(TypeDescriptor.GetProvider(selectedObject).GetTypeDescriptor(selectedObject)); 

// iterate through properies in the supplied object/type 
foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(selectedObject)) 
{ 
    // for every property that complies to our criteria 
    if (pd.Name.EndsWith("x") || pd.Name.EndsWith("y")) 
    { 
    // we first construct the custom PropertyDescriptor with the TypeDescriptor's 
    // built-in capabilities 
    PropertyDescriptor pd2 = 
     TypeDescriptor.CreateProperty(
      selectedObject.GetType(), // or just _settings, if it's already a type 
      pd, // base property descriptor to which we want to add attributes 
     // The PropertyDescriptor which we'll get will just wrap that 
     // base one returning attributes we need. 
      new CategoryAttribute("Location") 
     // this method really can take as many attributes as you like, 
     // not just one 
     ); 

    // and then we tell our new PropertyOverridingTypeDescriptor to override that property 
    ctd.OverrideProperty(pd2); 
    } 

} 

// then we add new descriptor provider that will return our descriptor istead of default 
TypeDescriptor.AddProvider(new TypeDescriptorOverridingProvider(ctd), selectedObject);