1

質問があります。実行時にデータ クラスの一部のプロパティのカテゴリ属性を設定したいと考えています。データ クラスが自動生成され、設計時の生成中にカテゴリを設定できません。

以下を使用して、実行時に 2 つのプロパティのカテゴリを設定しましたが、残念ながら、2 番目のパラメーターのカテゴリ属性を設定すると、最初のパラメーターのカテゴリも変更されます....何が欠けていますか?

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 を手動で設定する必要があります。私はこのようにしたくありませんが、実行時に設定します...

この追加情報が役立つかもしれません??

4

1 に答える 1

1

私は問題を解決しました!この回答の使用:実行時にプロパティレベルの属性を TypeDescriptor に追加する方法は?

私は2つのクラスを作成しました

  • PropertyOverridingTypeDescriptor.cs
  • TypeDescriptorOverridingProvider.cs

私の更新メソッドに次のスニペットを配置しました(上記の回答リンクに記載されているように):

// 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);
于 2013-10-22T06:53:11.890 に答える