Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing the PropertyGrid's Description and Category attributes at runtiome

I'm working on a business application that use the PropertyGrid. My project leader want me to localize the texts in the PropertyGrid at runtime. Hurray!!! irony

I have tried many days to localize the PropertyGrid. But I have trouble changing the attributes Description and Category at runtime. Changing the DisplayName works fine.

I have made a simple example to reproduce the issue: Create a Windows Form application and from the ToolBox add a PropertyGrid and a Button with default settings.

Here is the class I would like to display in the PropertyGrid:

class Person
{
    int age;

    public Person()
    {
        age = 10;
    }

    [Description("Person's age"), DisplayName("Age"), Category("Fact")]
    public int Age
    {
        get { return age; }
    }
}

In the Form's constructor; I create the Person object and display it in the PropertyGrid.

    public Form1()
    {
        InitializeComponent();
        propertyGrid1.SelectedObject = new Person();
    }

The button is used to change the DisplayName, Description and Category attributes at runtime.

    private void button1_Click(object sender, EventArgs e)
    {
        SetDisplayName();
        SetDescription();
        SetCategory();

        propertyGrid1.SelectedObject = propertyGrid1.SelectedObject;  // Reset the PropertyGrid
    }

The SetDisplayName() method works fine and actually changes the DisplayName of the property in runtime!

    private void SetDisplayName()
    {
        Person person = propertyGrid1.SelectedObject as Person;
        PropertyDescriptor descriptor = TypeDescriptor.GetProperties(person)["Age"];
        DisplayNameAttribute attribute = descriptor.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
        FieldInfo field = attribute.GetType().GetField("_displayName", BindingFlags.NonPublic | BindingFlags.Instance);
        field.SetValue(attribute, "The age");
    }

SetDescription() and SetCategory() methods are almost identical to the SetDisplayName() method, except for some type changes and strings to access the private member of each attributes.

    private void SetDescription()
    {
        Person person = propertyGrid1.SelectedObject as Person;
        PropertyDescriptor descriptor = TypeDescriptor.GetProperties(person)["Age"];
        DescriptionAttribute attribute = descriptor.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
        FieldInfo field = attribute.GetType().GetField("description", BindingFlags.NonPublic |BindingFlags.Instance);
        field.SetValue(attribute, "Age of the person");
    }

    private void SetCategory()
    {
        Person person = propertyGrid1.SelectedObject as Person;
        PropertyDescriptor descriptor = TypeDescriptor.GetProperties(person)["Age"];
        CategoryAttribute attribute = descriptor.Attributes[typeof(CategoryAttribute)] as CategoryAttribute;
        FieldInfo[] fields = attribute.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
        FieldInfo field = attribute.GetType().GetField("categoryValue", BindingFlags.NonPublic | BindingFlags.Instance);
        field.SetValue(attribute, "Info");
    }

Both SetDescription() and SetCategory() methods compile and run but don't effext the ProperytGrid. After the last line of each method you can use the IntelliSense to see that the the Attribute object (DescriptionAttribute and CategoryAttribute) has a member that has changed.

After running these three methods and resetting the PropertyGrid (see button1 click method); the PropertyGrid has only changed the DisplayName attribute. The Description and the Category attributes are unchanged.

I would really like some help to solve this issue. Please any suggestion or solutions?

Note 1: I don't want any responses saying that this is impossible and the attributes can only be set at design time. That is not true! This article from CodeProject.com show an example how to localize the PropertyGrid and to change the attributes in runtime. Unfortunately I have problem scoping the example for those parts I need to solve this issue.

Note 2: I would like to avoid using resouce files. This is due to the localization is located in different language files. Each file contain a bunch of indices, each with a string value. All indices and string values are loaded into Dictionary object. To access a string the index is used to access it. I most, unfortunately, use this solution.

Best regards, /Mc_Topaz

like image 453
Mc_Topaz Avatar asked Oct 01 '22 11:10

Mc_Topaz


2 Answers

Here is a good article for Globalized-property-grid

You can give many resource file for the Person ,than will the propery-grid will localize.

Here is three step:

  1. inherit from GlobalizedObject
  2. Give the resource file for Person with the same name (eg.Person.zh-cn.resx)
  3. change the thread's cuture which you want to display.

You can try ,Good Luck!

like image 120
huoxudong125 Avatar answered Oct 03 '22 01:10

huoxudong125


What you could do is reuse the DynamicTypeDescriptor class described in my answer to this question here on SO: PropertyGrid Browsable not found for entity framework created property, how to find it?

like this:

  public Form1()
  {
      InitializeComponent();

      Person p = new Person();

      DynamicTypeDescriptor dt = new DynamicTypeDescriptor(typeof(Person));
      propertyGrid1.SelectedObject = dt.FromComponent(p);
  }

  private void button1_Click(object sender, EventArgs e)
  {
      DynamicTypeDescriptor dt = (DynamicTypeDescriptor)propertyGrid1.SelectedObject;
      DynamicTypeDescriptor.DynamicProperty dtp = (DynamicTypeDescriptor.DynamicProperty)dt.Properties["Age"];

      dtp.SetDisplayName("The age");
      dtp.SetDescription("Age of the person");
      dtp.SetCategory("Info");

      propertyGrid1.Refresh();
  }
like image 27
Simon Mourier Avatar answered Oct 03 '22 00:10

Simon Mourier