Click here to Skip to main content
Click here to Skip to main content

Globalized Property Grid - Revisited

, 14 Jun 2003
Rate this:
Please Sign up or sign in to vote.
This article introduces localization of category names in a globalized property grid control and considers inheritance issues.
<!-- Add the rest of your HTML here -->

Sample Image 

Sample Image

Introduction

In my article 'Globalized property grid' I demonstrated how to localize the property names of an object. This article is based on this article incrementally.  

Corresponding to questions I would like to address following topics here:

  • Localizing category names
  • Inheritance of globalized objects

Localizing category names were left out in my previous article although it is as much of interest. However, localization support of category names is limited as you will see below.

Another question I want to answer is regarding inheritance of objects. Although I answered the question on my previous article, I still want to address it here.

Let's start with category names first.

Category names

A property grid is able to organize the properties of an object in categories. You can assign a category to the properties of your objects by using an attribute of type  CategoryAttribute.

Here is an example how to assign the property LastName to a category named Required Data:

[Category("Required Data")]
public string LastName { get {...}; set {...}; } 

If no category attribute is assigned to a property, then a property will be assigned to a default category that you can find in a static property called CategoryAttribute.Default  ("Misc").

CategoryAttribute has a property called Category that is used to access the category name.

If you use category names in a globalized property grid then it is wishful to have the category names localized, too.  

Localizing category names

There is support included to localize a category name.

You cannot override the Category  property to return a lolcalized string. Instead, the first time the Category property is accessed CategoryAttribute will call an overridable method called GetLocalizedString. This method has a protected scope and is overridable. Derive your own class from CategoryAttribute and override GetLocalizedString. You get the assigned category name (see "Required Data" in the example above) as a parameter and may return a localized string instead:

[AttributeUsage(AttributeTargets.Property, AllowMultiple=false, 
   Inherited=true)]
class GlobalizedCategoryAttribute : CategoryAttribute
{
  string table = "";
  ...
  protected override string GetLocalizedString( string value )
  {
    string baseStr = base.GetLocalizedString( value );
    // Now use resource table name to access the resources.  
    ResourceManager rm = 
       new ResourceManager(table, Assembly.GetExecutingAssembly() );
    // Get the string from the resources.
    try
    {
      return rm.GetString(value);
    }
    catch( Exception )
    {
      return value;
    }
  }
}

Use this class to decorate a property:

[GlobalizedCategory("Required")]
public string LastName { get {...}; set {...}; } 

GlobalizedCategoryAttribute uses the original category names as a symbolic name for accessing the resources. The member table optionally specifies the resource table and may be set either explicitly. If no resource table name is provided, the class name will be used as the table name (see sample).

But there is a big drawback in the implementation of CategoryAttribute provided by the .NET framework (version 1.0). 

GetLocalizedString is only called once on the first access. The consequence is we are able to select a language on startup only. The it will work fine. And maybe this will be sufficient for a lot of applications. In case of switching the language at runtime, it will not work. I demonstrate this issue in the sample provided. On startup you can select a language. you'll see the property and category names are displayed in the selected language. Pressing the button on the dialog to select another language works for property names only, category names don't change. 

I don't know if the behaviour of the CategoryAttribute class has changed in .NET Framework 1.1. Maybe the community can answer.

Let's get over to the second topic to address.

Inheritance of globalized objects

In the sample of my previous article (Globalized property grid) I just used one class called Person inheriting the GlobalizedObject. Using the defaults the localized property names were extracted from the resource file Person.resx or Person.en.resx. If you have tried the sample code and enhanced it by deriving from Person class, then the property names of the derived classes may not be shown. Even though you have placed localized strings in the resource file person.resx.     

The answer is relatively simple. By default, the class name will be used to access a localized resource. That means, The person class gets its localized names from person.resx. So, a derived class Employee gets its localized names from Employee.resx.

If you want to use one resource file only, you have to tell it explicitly. Here two options are possible.

Using the GlobalizedPropertyAttribute class where you can explicitly name the resource table to use on every property individually. Referring to the person.resx resource table may be done as follows:

// Use the provided resource table instead of the default one which 
// would be determined by the class name. The first parameter is 
// the key of the property in the string table. Leaving it empty 
// indicates to use the property name by default.

[GlobalizedProperty("",Table="GlobalizedPropertyGrid.Person")]
public string Department
{
  get { return department; }
  set { department = value; }
}
        
        

Alternatively, an attribute class may be additional used to define the resource table name on the class level.  This is demonstrated by a class GlobalizedObjectAttribute, which contains one property only that specifies a resource table to access. For example, to access a resource table named SpecialStringTable use it as follows:

[GlobalizedObjectAttribute("GlobalizedPropertyGrid.SpecialStringTable")]
public class Employee : Person
{ 
   ...

The class GlobalizedPropertyDescriptor detects the resource table name by using the following sequence (see implementation of the properties DisplayName and Description):

  1. Check, if there's a GlobalizedPropertyAttribute on property level.
    If yes, additionally check if there is a resource table specified.
  2. If no resource table name provided yet, check, if a GlobalizedObjectAttribute is provided on the class level.
  3. If still no resource table name provided yet, use the class name. 

Creating a sample project

For demonstration purpose I have extended the sample project. For a detailed description of the sample project refer to the previous article (Globalized property grid). There are only some modifications and additions:

Demonstrating localization of categories

I have added an attribute class called GlobalizedCategoryAttribute (Attributes.cs) to localize category names. This attribute is applied to the properties as mentioned above. To demonstrate that selecting a language is possible on startup only, I have modified the application a bit. On startup a dialog box will be displayed to select a language.

Selecting a language

Selecting a language (e.g. English) at this time works for localized category names. The category and property names will be displayed in the selected language in the property grid on the main form. 

Switching the current language (e.g. to German) by pressing the button in the upper right corner on the main form doesn't affect the category names. Property names have changed correctly.

Maybe this limited behaviour of the CategoryAttribute class will change in future releases. 

Demonstrating localization of properties in case of inheritance

I have added an attribute class called GlobalizedObjectAttribute (Attributes.cs) to specify a custom resource table name on class level.

I also have added a class Employee (Employee.cs) inheriting the Person class to demonstrate inheritance. 

// Employee.cs
/// <SUMMARY>
/// Employee derives from Person and so is a globalized object implicitly.
/// 
</SUMMARY>
public class Employee : Person
{
  private string department = "";

  public Employee()
  {
  }

  public string Department
  {
    get { return department; }
    set { department = value; }
  }
}
        

This class will be instantiated by the Form1 class:

// Instantiate test class and set some data
Employee emp = new Employee();
emp.FirstName = "Max";
emp.LastName = "Headroom";
emp.Age = 42;
emp.Department = "Channel5";

this.person = emp;        

 Employee.resx and Employee.en.resx have been to have the property names of Employee displayed correctly.

Employee resource table

Summary

This article is an incremental version of its base article Globalized property grid . It discusses the localization of category names and localized property names in case of inheritance.  

To localize the category names there are two steps necessary:

  • Create a class and derive it from CategoryAttribute and override the method GetLocalizedString. This method should retrieve the localized string from a resource table.
  • Add this attribute to your properties. Provide a name for the category that will be used as a key to the resource string table.

But note:CategoryAttribute only reads the localized string on the first access of the category name. Switching languages at runtime is not possible.

Supporting inherited classes based on the sample provided requires to either define a resource string table for each class with the name of the class or referring to a certain resource table by explicit usage of custom attributes: GlobalizedPropertyAttribute on property level or GlobalizedObjectAttribute on class level.    

References

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Gerd Klevesaat
Web Developer
Germany Germany
For ten years I worked as a senior consultant, coach, lead architect and project lead for several consulting companies.
Currently I work as a system architect for Zuehlke Engineering GmbH based in Frankfurt.
You can find a detailed resume here.

Comments and Discussions

 
QuestionFunny fact about DisplayNameAttribute, DescriptionAttribute and CategoryAttribute PinmemberAndy4114-Oct-12 1:01 
GeneralMy vote of 5 Pinmembermanoj kumar choubey29-Feb-12 19:05 
GeneralUsing this code with generics [modified] PinmemberStefan Schwarzbach13-Feb-09 4:01 
GeneralBest Localization Plug-in for Visual Studio. PinmemberAlexander Nesterenko17-Dec-08 22:37 
GeneralGlobalizedCategoryAttribute Pinmemberppbb10-Oct-05 3:35 
Generalplease help me Pinmembersreejith ss nair18-Sep-05 22:17 
GeneralHiding Control Properties PinmemberVarun Gulati3-Jan-05 0:51 
GeneralRe: Hiding Control Properties PinmemberGerd Klevesaat4-Jan-05 3:39 
Questionarabic property grid? Pinmemberdinaayoub11-Oct-04 18:37 
GeneralGlobalization of the tooltips Pinmemberaagirre9-Sep-04 21:13 
GeneralInterfaces and category limitations Pinmemberpicho8-Jun-04 4:34 
GeneralRe: Interfaces and category limitations Pinmemberwout de zeeuw19-Aug-04 2:50 
GeneralGlobalized and nested Pinmemberpestes12-May-04 21:33 
GeneralTips if scrollbar dissapears PinmemberGrut12-May-04 1:53 
GeneralProperty Grid and File Open Dialog Pinmemberw36a4-Feb-04 13:52 
GeneralVery Great but.. PinmemberNycos13-Jan-04 22:42 
GeneralLocalizing the property value in an enum PinsussPaulS19-Nov-03 12:45 
GeneralRe: Localizing the property value in an enum PinmemberGerd Klevesaat19-Nov-03 23:06 
GeneralLocalizing the property value in an enum PinsussAnonymous19-Nov-03 12:29 
GeneralRTL & LTR!!!!????!!!! Pinmemberomoshima7-Aug-03 6:04 
GeneralLocalization of category names PinmemberGerd Klevesaat18-Jun-03 5:31 
GeneralNot All Strings show up localized PinmemberPaulS16-Jun-03 18:07 
GeneralRe: Not All Strings show up localized PinmemberGerd Klevesaat17-Jun-03 0:24 
GeneralRe: Not All Strings show up localized PinmemberPaulS17-Jun-03 4:04 
GeneralRe: Not All Strings show up localized PinmemberGerd Klevesaat17-Jun-03 4:30 
GeneralUsing an interface rather than inheritance PinmemberBill Seddon15-Jun-03 12:31 
GeneralRe: Using an interface rather than inheritance PinmemberGerd Klevesaat16-Jun-03 23:51 
GeneralRe: Using an interface rather than inheritance PinmemberMichael Coyle20-Mar-05 9:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141220.1 | Last Updated 15 Jun 2003
Article Copyright 2003 by Gerd Klevesaat
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid