Dienstag, 27. Oktober 2009

Dot Net (C#): lokalisiertes PropertyGrid ; lokalisierte Attribute

In der heutigen Zeit wird eine Anwendung meistens für mehrere Sprachen realisiert. Mit Microsoft .NET ist es kein Problem, Windows-Anwendungen zu lokalisieren. Doch immer wieder kommt die Frage auf, wie man Attribute, insbesondere solche für das PropertyGrid (Description, DisplayText, Category), lokalisieren kann.

Da meine Internetrecherche zu diesem Thema kaum brauchbare Beispiele hervorbrachte, möchte ich an einem Minimalbeispiel darauf eingehen:

Als erstes brauchen wir eine Klasse, die lokalisiert werden soll, nehmen wir in diesem Fall eine "Person":

namespace LocalizeableDescriptionPropertyGrid
{
public class Person
{
// Properties
public String FirstName { get; set; }
public String LastName { get; set; }

// ctor
public Person(string fName, string lName)
{
this.FirstName = fName;
this.LastName = lName;
}

// other methods ...
}
}

Normalerweise würde man die Klasse nun wir folgt mit Attributen versehen:
[DescriptionAttribute("Der Vorname dieser Person")]
public String FirstName { get; set; }

[DescriptionAttribute("Der Nachname dieser Person")]
public String LastName { get; set; }

Diese Vorgehensweise hat jedoch den Nachteil, dass die Attribute nicht lokalisierbar sind. Leider gibts es in .NET keine Möglichkeit, solche Attribute problemlos zu lokalisieren, da deren Information von der Laufzeitumgebung einmal eingelesen wird (per Reflection) und danach nicht mehr aktualisiert. Mit einem kleinen Trick kann man jedoch zumindest dafür sorgen, dass genau in diesem Momemt die Attribute der Sprache angepasst werden. Dazu ist es als erstes notwendig, die lokalisierten Texte wie gewohnt in einer beliebigen Resource-Datei abzulegen.



Als nächstes muss eine Klasse her, die es einem Attribut ermöglicht, seine Informationen aus einer Resource-Datei zu laden. Ich zeige das Verfahren am Beispiel des Description-Attributes, es kann alternativ mit dem Category- und DisplayText-Attribut verfahren werden:

Lediglich ein privates Feld (oder Property) sowie das Überschreiben des Get-Property sind notwenidg.
public class LocalizedDescriptionAttribute : DescriptionAttribute
{
/// <summary>
/// Contains the name of the resource-string
/// </summary>
private string rDescription;

/// <summary>
/// Creates a new LocalizedDescription Attribute instance
/// giving it the name of the resource-string
/// </summary>
/// <param name="description"></param>
public LocalizedDescriptionAttribute(string description)
{
this.rDescription = description;
}

/// <summary>
/// (Overridden) Get: fetching the description during runtime
/// from the Resources (with respect to the current culture)
/// </summary>
public override string Description
{
get
{
return Properties.Resources.ResourceManager.GetString(
this.rDescription,
Thread.CurrentThread.CurrentCulture
);
}
}
}

Als nächstes ist es notwendig, die Klasse Person abzuändern und das neue Attribut einzusetzen:
namespace LocalizeableDescriptionPropertyGrid
{
public class Person
{
// Properties
[LocalizedDescriptionAttribute("PersonFirstName")]
public String FirstName { get; set; }
[LocalizedDescriptionAttribute("PersonLastName")]
public String LastName { get; set; }

// ctor
public Person(string fName, string lName)
{
this.FirstName = fName;
this.LastName = lName;
}

// other methods ...
}
}


Eine fertige Klasse könnte wie folgt aussehen:
namespace LocalizeableDescriptionPropertyGrid
{
public class Person
{
// Properties
[LocalizedCategoryAttribute("PersonCatData"),
LocalizedDescriptionAttribute("PersonFirstNameDescription"),
LocalitedDisplayTextAttribute("PersonFirstNameDisplayText")]
public String FirstName { get; set; }

[LocalizedCategoryAttribute("PersonCatData"),
LocalizedDescriptionAttribute("PersonLastNameDescription"),
LocalitedDisplayTextAttribute("PersonLasttNameDisplayText")]
public String LastName { get; set; }

// other properties

// ctor
public Person(string fName, string lName)
{
this.FirstName = fName;
this.LastName = lName;
}

// other methods ...
}
}


Das gesamte Beispiel könnt ihr hier runterladen: localizablepropgridcode.rar (14,6 KB)

1 Kommentar:

Unknown hat gesagt…

Hallo Herr Schneider
Funktioniert in VB mit [DisplayNameAttribute] und [DescriptionAttribute] ausgezeichnet. Doch leider bekomme ich beim analogen Implementieren von [CategoryAttribute] den Fehler [Property "CategoryAttribute" kann nicht als "Overrides" deklariert werden, da es property in Basis class nicht überschreibt.]
Für Ihre Hilfe bin ich Ihnen ausserordentlich dankbar; ich komme echt nicht weiter.
Freundliche Grüsse
Toni Dalvai