Daily Archives: 29.10.2010

Sprachumschaltung und WPF

Wer mit .NET “aufgewachsen” ist, der kennt das System.Threading.Thread.CurrentThread.CurrentCulture bzw. CurrentUICulture. Damit kann man z.B. in WinForms-Anwendungen die Formatierungen der Ausgaben beeinflussen. Diese Culture wird auch in den meisten Objekten verwendet wenn man “ToString()” aufruft. Bestes Beispiel dafür ist DateTime. Intern wird hier die aktuelle Culture (CurrentCulture) des aktuellen Threads verwendet.

Dieses ganze Konzept ist aber nicht so ganz WPF kompatibel. Dazu gibt es zwei Gründe: Erstens basiert bei WPF (fast) alles auf DependencyProperties, welche Vererbung und auch Änderungsbenachtrichtigungen schon automatisch unterstützen. Auch spielen die Converter eine große Rolle beim Anzeigen von Daten. Dabei wird immer eine Culture mitgegeben in den Konvertierungsmethoden mitgegeben. AUs diesem Grunde spielt die “Thread.CurrentThread.CurrentCulture” in WPF keine Rolle mehr!

Die Sprache wird in WPF also auch über ein DependencyProperty umgeschaltet: FrameworkElement.Language

Das kann man einfach testen indem man z.B. ein DateTime-Property an an TextBlock bindet. Dabei wird die Datum/Uhrzeit immer in en-us angezeigt! Egal welche Sprache nun das Betriebssystem oder den Benutzer hat. Ob dies ein Bug oder Feature ist, sei mal dahingestellt.

Um also beim Starten der Applikation die Sprache auf die aktuelle Sprache zu setzen, muss man für jedes TopLevel-Fenster das Language Property korrekt initialisieren, am besten im Konstruktor:

this.Language = 
  System.Windows.Markup.XmlLanguage.GetLanguage(
    System.Threading.Thread.CurrentThread.CurrentUICulture.Name
  );

Will man eine Sprachumschaltung dynamisch machen, so könnte man auch ein Binding auf dieses Language-Property machen. Dazu muss man aber wissen, dass ja jedes Binding auch eine Culture hat. Da aber die Culture aus dem vererbeten “Language” DependencyProperty kommt beisst sich hier die Katze in den Schwanz… aus diesem Grund scheitert auch ein Binding der Form:

Language={Binding MyCurrentCulture.Name}

mit der Fehlermeldung (InnerException):
Binding for property 'Language' cannot use the target element's Language for conversion; if a culture is required, ConverterCulture must be explicitly specified on the Binding.
Wer diese Meldung genau liest erkennt, dass man für den Converter die Culture explizit vorgeben muss! Damit muss der Bindning Ausdruck z.B. wie folgt aussehen:

Language={Binding MyCurrentCulture.Name,
  ConverterCulture={x:Static glob:CultureInfo.InvariantCulture}}

Dabei ist der Namespace “glob”:

xmlns:glob="clr-namespace:System.Globalization;assembly=mscorlib"

Damit wird nun das Binding möglich.
Und natürlich wird jedes Binding nochmals ausgeführt (bzw. der passende Converter aufgerufen), bei welcher die Language vererbt wurde (was eigentlich überall der Fall ist).
Man sieht also auch: Die Anzeige wird nicht nicht bei Werteänderung aktualisiert, sondern auch bei “Language-Property” Änderung 😉

Anbei mal ein ganz kleines Testprojekt, welches das Umschalten der Language zur Laufzeit anhand dem DateTime aufzeigt:
WpfCulture.zip