While developing an application for my company, I had to use a PropertyGrid (default WinForms-usercontrol).
The problem was the localization of this grid.
The client wanted to localize the categories, property-names, enum selection values and the descriptions.
So I did some research and developed a couple of handy classes that can do the job.
The first step was to create some resx resource files:
Used for Description and Categories
Used for enum-value- and propertyname localizations.
( I created them by clicking on the project and adding a new resource file )
The first class we need is a class to localize the descriptions visible in the PropertyGrid control.
The second class we need is a class to localize the categories in the PropertyGrid control.
Image a test-class InfoMessage for using the attributes above:
(This class is just a class from my project, look at the attributes located above the property declarations of Message and Title)
The third class/part is to create some classes that can localize the Property-names displayed in the PropertyGrid. This is a little bit nifty because the control uses reflection to get the property-names that it's going to display.
The client want to replace the property-name 'Message' with the localized dutch value 'Bericht:' for example.
The things we must do to get this job done:
- Create an attribute for defining which property to change
It's not needed when the values are formatted in a certain way in the resource file.
The format is: classname_propertyname
- Create a custom PropertyDescriptor to fetch the localized description values.
- Create an object that implements ICustomTypeDescriptor so that the 'GetProperties' method is overridden. This method is called by the PropertyGrid when it requests the names of the properties that it wants do display.
This knowing, we can start programming the actual classes.
The Attribute (1):
The PropertyDescriptor (2):
The base-class where we have to inherit from with the localizable objects (3):
Now, this in mind, look back at the InfoMessage test-class. It inherits from Concurrency (it's an object of me to keep track of concurrency), and the Concurrency object inherits from the GlobalizedObject.
As far as the implementions it's done. Now we have to adjust the resource file(s).
The PropertyDescriptor uses the PropertyNames resource file(s), to get the localized values for the keys.
The descriptor makes it's own keys, all you have to is fill them in in the resource file.
Something like this:
If you supply an InfoMessage object to the PropertyGrid, then it will be localized.
The only problem now is the localization of enum-values if you have enums in the class that you want to supply to the PropertyGrid.
For localizing the enum-values, we need a TypeConverter, more specific the EnumConverter from .NET
We have to inherit from it to create our own converter.
And we have to cache the relation between the localized values and the original enum-values.
The converter looks like this:
If you want to use it, take your enum-declaration and put the TypeConverterAttribute above it:
Look at the resource image for seeing the declaration of the keys needed to localize this enum-values.
Mind the [TypeConverter(typeof(GlobalEnumConverter))] attribute on top of the declaration, that line makes sure that the converter is used when the PropertyGrid wants to display the enum-values.
Just change your Culture of you current thread and see that the PropertyGrid will change it's values ;)
Hope this helps, if there are any questions, you know where to find me.