StringFormat-Lokalisierungsprobleme in wpf


112

In WPF 3.5SP1 verwende ich die letzte Funktion StringFormat in DataBindings:

     <TextBlock Text="{Binding Path=Model.SelectedNoteBook.OriginalDate, StringFormat='f'}"
                FontSize="20" TextTrimming="CharacterEllipsis" />

Das Problem ist, dass das Datum immer in Englisch formatiert ist ... obwohl mein System in Französisch ist? Wie kann ich erzwingen, dass das Datum dem Systemdatum folgt?


14
3 Jahre eine hoch bewertete Frage, aber keine Antwort markiert! Überall traurige Gesichter.
Gusdor

Antworten:


211
// Ensure the current culture passed into bindings is the OS culture.
// By default, WPF uses en-US as the culture, regardless of the system settings.
FrameworkElement.LanguageProperty.OverrideMetadata(
      typeof(FrameworkElement),
      new FrameworkPropertyMetadata(
          XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

Vom Erstellen eines internationalisierten Assistenten in WPF


17
Ja das ist ziemlich nervig. +1
Szymon Rozga

2
Vielen Dank, dass Sie meine Kopfschmerzen gelöst haben.
Skurmedel

9
Toll. Was ist jedoch zu tun, wenn sich die Kultur während des Lebenszyklus der Anwendung ändert (z. B. kann der Benutzer seine bevorzugte Kultur in einem Einstellungsdialog ändern)? Gemäß der Dokumentation kann FrameworkElement.LanguageProperty.OverrideMetadata nicht mehr als einmal aufgerufen werden (es wird eine Ausnahme
ausgelöst

1
@pengibot Diese Lösung funktioniert bei mir. Ich verwende .net 4 / C # / WPF und habe den Code in die OnStartup-Methode eingefügt.
Björn

17
Beachten Sie, dass das Run- Element nicht von FrameworkElement erbt. Wenn Sie also Daten usw. an einen Run binden, benötigen Sie einen zusätzlichen Aufruf für typeof (System.Windows.Documents.Run)
Mat Fergusson,

90

Definieren Sie den folgenden XML-Namespace:

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

Nun sehen Sie diese fantastische Lösung:

<TextBlock Text="{Binding Path=Model.SelectedNoteBook.OriginalDate, StringFormat='f', ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}" FontSize="20"TextTrimming="CharacterEllipsis" />

Mir ist klar, dass dies kein globaler Fix ist und Sie ihn für jede Ihrer Bindungen benötigen, aber das ist doch nur eine gute XAML? Soweit mir bekannt ist, wird bei der nächsten Aktualisierung der Bindung die richtige CultureInfo.CurrentCultureoder die von Ihnen angegebene verwendet.

Diese Lösung aktualisiert Ihre Bindungen sofort mit den richtigen Werten, aber es scheint viel Code für etwas so Seltenes und Unschädliches zu sein.


4
Ausgezeichnet! Das hat wunderbar funktioniert! Ich habe kein Problem damit, dies zu den wenigen Stellen hinzuzufügen, an denen es benötigt wird.
Übrigens

3
Ausgezeichnete Arbeit. Es ist so seltsam, dass WPF im Gegensatz zur aktuellen Kultur standardmäßig US-Englisch verwendet.
Kris Adams

12

Ich wollte nur hinzufügen, dass die Antwort von Loraderon in den meisten Fällen großartig funktioniert. Wenn ich die folgende Codezeile in meine App.xaml.cs einfüge, werden die Daten in meinen TextBlocks in der richtigen Kultur formatiert.

FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

Ich sage "die meisten Fälle". Zum Beispiel wird dies sofort funktionieren:

<TextBlock Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}}" />
--> "16 mei 2013" (this is in Dutch)

... aber wenn Sie Runs in einem TextBlock verwenden, wird die DateTime in der Standardkultur formatiert.

<TextBlock>
  <Run Text="Datum: " />
  <Run Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}, Mode=OneWay}" />
</TextBlock>
--> "Datum: 16 may 2013" (this is in English, notice the
    name of the month "may" vs. "mei")

Damit dies funktioniert, brauchte ich Gusdors Antwort, nämlich ConverterCulture = {x: Static gl: CultureInfo.CurrentCulture} zur Bindung hinzuzufügen.

<TextBlock>
  <Run Text="Datum: " />
  <Run Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}, ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}, Mode=OneWay}" />
</TextBlock>
--> "Datum: 16 mei 2013" (=Dutch)

Ich hoffe, diese zusätzliche Antwort wird jemandem von Nutzen sein.


In der Tat leitet sich Run nicht von FrameworkElement ab. Sie können versuchen, die Antwort von Loraderon zu ändern, um seinen Code für die Basis von Run (FrameworkContentElement) sowie für FrameworkElement zu wiederholen.
Nathan Phillips

Für diejenigen, die sich fragen könnten: xmlns: gl = "clr-Namespace: System.Globalization; Assembly = mscorlib"
Igor Meszaros

11

Fügen Sie einfach die Kulturverknüpfung zum Tag der obersten Ebene ein:

xml:lang="de-DE"

z.B:

<Window x:Class="MyApp"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xml:lang="de-DE"
    Title="MyApp" Height="309" Width="497" Loaded="Window_Loaded">....</Window>

5
Dies ist jedoch genauso schlimm wie die Annahme, dass en-US die „richtige“ Kultur ist. Es sollte eher die Einstellungen vom Computer des Benutzers übernehmen.
Fehlbezeichnung

Vielen Dank, genau das habe ich gesucht! Wenn WPF der Meinung ist, dass en-EN für jede Situation die richtige Kultur ist, kann ich dies auch mit meiner eigenen Lokalisierung tun. Da ich an einer Proof-of-Concept-Anwendung arbeite, bei der die Entwicklungsgeschwindigkeit an der Tagesordnung ist, bleibt keine Zeit, mit Dutzenden von Codezeilen herumzuspielen, nur um eine einzelne dazu DatePickerzu bringen, ihre Arbeit zu erledigen mich schnell wieder auf dem richtigen Weg!
M463

Die beste Antwort für meinen Fall, ich habe endlich nach Ewigkeiten gesucht :) und natürlich ist es richtig, entweder Sie nehmen an, dass es sich um ein US-amerikanisches oder ein de-DE-Problem handelt ... Menschen haben immer Probleme mit einfachen Lösungen -.-
MushyPeas

10

Wie bereits erwähnt, verwendet XAML standardmäßig die invariante Kultur (en-US), die Sie verwenden können

FrameworkElement.LanguageProperty.OverrideMetadata(
  typeof(FrameworkElement),
  new FrameworkPropertyMetadata(
      XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

um die Kultur auf die Standardkultur für die Sprache der aktuellen Kultur zu setzen. Aber der Kommentar ist falsch; Dies verwendet nicht die aktuelle Kultur, da Sie keine Anpassungen sehen, die der Benutzer möglicherweise vorgenommen hat. Dies ist immer die Standardeinstellung für die Sprache.

Um die aktuelle Kultur tatsächlich mit Anpassungen zu verwenden, müssen Sie die ConverterCulturezusammen mit der StringFormatwie in festlegen

Text="{Binding Day, StringFormat='d', ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}}"

mit dem glals global definierten Namespace in Ihrem Root-Element

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

Wenn Sie dies durch Code anstelle von XAML tun, ist es wie folgt:binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Metalogic

8

Wenn Sie die Sprache ändern müssen, während das Programm ausgeführt wird, können Sie einfach die Language-Eigenschaft Ihres Root-Elements ändern (ich bin mir nicht sicher, ob dies einen sofortigen Effekt hat oder ob das Unterelement neu erstellt werden muss, in meinem Fall funktioniert dies zumindest).

element.Language = System.Windows.Markup.XmlLanguage.GetLanguage(culture.IetfLanguageTag);

es wird sofort neu bewertet, muss aber leider für jedes einzelne Wurzelelement (Fenster)
separat eingestellt werden

6

Der vollständige Code zum Umschalten der Lokalisierung auch in Elementen wie <Run />diesen lautet:

Private Shared Sub SetXamlBindingLanguage()

    '' For correct regional settings in WPF (e.g. system decimal / dot or comma) 
    Dim lang = System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(TextElement), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(DefinitionBase), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(FixedDocument), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(FixedDocumentSequence), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(FlowDocument), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(TableColumn), New FrameworkPropertyMetadata(lang))
    FrameworkElement.LanguageProperty.OverrideMetadata(GetType(FrameworkElement), New FrameworkPropertyMetadata(lang))

End Sub

0

Wenn Sie die Kulturinformationen zur Laufzeit ändern möchten, können Sie ein Verhalten verwenden (siehe unten).

  public class CultureBehavior<TControl> : Behavior<TControl>
    where TControl : FrameworkElement
{
    private readonly IEventAggregator _eventAggregator;
    private readonly Action<CultureInfo> _handler;

    public CultureBehavior()
    {
        _handler = (ci) => this.AssociatedObject.Language = XmlLanguage.GetLanguage(ci.IetfLanguageTag);
        _eventAggregator = IoC.Container.Resolve<IEventAggregator>();
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        _eventAggregator
            .GetEvent<LanguageChangedEvent>()
            .Subscribe(_handler);

        _handler.Invoke(CultureInfo.CurrentCulture);
    }

    protected override void OnDetaching()
    {
        _eventAggregator
            .GetEvent<LanguageChangedEvent>()
            .Unsubscribe(_handler);

        base.OnDetaching();
    }
}

0

Wenn Sie nicht an XAML, sondern an Code arbeiten, können Sie die ConverterCulture wie folgt festlegen:

binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;

Ein großes Lob an @KZeise für den Hinweis auf den subtilen Unterschied zwischen der Verwendung der Standardkulturdefinition und der Verwendung der benutzerdefinierten Kulturdefinition des Benutzers.


-3

Verwenden Sie Label (einschließlich Cultture) und nicht Texblock

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.