Verwenden Sie „echte“ CultureInfo.Currentculture in WPF -Bindung, nicht CultureInfo von Ietflanguagetag

StackOverflow https://stackoverflow.com/questions/5831455

Frage

In meinem Fall:

Ich habe eine Textblockbindung an eine Eigenschaft von Typ DateTime. Ich möchte, dass es so angezeigt wird, dass die regionalen Einstellungen des Benutzers sagen.

<TextBlock Text="{Binding Date, StringFormat={}{0:d}}" />

Ich setze Spracheigenschaft als WPF XAML -Bindungen und Stromkulturanzeigesagt:

this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);

Mit dieser Codezeile wird der Text jedoch nur als Standardformat von CultureInfo mit iETFlanguagetag von CurrentCulture angezeigt, nicht als effektiver Wert, der in den Einstellungen der Systemregion ausgewählt wurde:

(zB für "DE-de" DD / MM / JJJJ wird anstelle von ausgewählt yjyy-mm-dd)

Region settings: not the default but yyy-MM-dd is used

Gibt es eine Möglichkeit, wie Bindung das richtige Format verwendet, ohne die Konverterkultur bei jeder einzelnen Bindung zu definieren?

In Code

string.Format("{0:d}",Date);

verwendet die richtigen Kultureinstellungen.

bearbeiten:

Eine andere Möglichkeit, die nicht wie gewünscht funktioniert (wie diese.language = ... tut):

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

und

<Binding Source="{x:Static glob:CultureInfo.CurrentCulture}" 
 Path="IetfLanguageTag" 
 ConverterCulture="{x:Static glob:CultureInfo.InvariantCulture}" />
War es hilfreich?

Lösung

Sie können eine Unterklasse der Bindung (z. B. CultureAwarding) erstellen, die die Konverterkultur beim Erstellen automatisch auf die aktuelle Kultur setzt.

Es ist keine perfekte Lösung, aber es ist wahrscheinlich die einzige, da die Bindung, die Kultur rückwirkend zu verhindern, einen anderen Code in WPF brechen könnte, was von diesem Verhalten abhängt.

Lassen Sie mich wissen, wenn Sie mehr Hilfe brauchen!

Andere Tipps

Dies ist eine Erweiterung der Antwort von Akzent. Sie schlugen vor, dass wir eine Unterklasse der Bindungsklasse erstellen und die Konverterkultur auf die Stromkultur einstellen sollten. Obwohl die Antwort sehr einfach ist, bin ich der Meinung, dass einige Leute es möglicherweise nicht sehr wohl fühlen, sie zu implementieren, daher teile ich die Codeversion von Akzents Antwort mit einem Beispiel dafür, wie sie in XAML verwendet werden.

using System;
using System.Globalization;
using System.Windows.Data;

namespace MyWpfLibrary
{
    public class CultureAwareBinding : Binding
    {
        public CultureAwareBinding()
        {
            ConverterCulture = CultureInfo.CurrentCulture;
        }
    }
}

Beispiel dafür, wie man dies in XAML verwendet

1) Sie müssen Ihren Namespace in Ihre XAML -Datei importieren:

<Page
    ...
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:myWpfLib="clr-namespace:MyWpfLibrary;assembly=<assembly_name>"
    ...
>

2) Nutzung der realen Welt des CultureaWareBinding

<Textblock Text="{myWpfLib:CultureAwareBinding Path=Salary, Source=Contact, StringFormat={}{0:C}}" />

Setzen Sie die folgende Codezeile ein, bevor eine Benutzeroberfläche initialisiert wird. Das hat für mich funktioniert.

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

(Und entfernen Sie alle explizite Kulturparameter)

Ihr zweiter Versuch war nahe und führte mich zu einer Lösung, die für mich funktioniert.

Das Problem beim Einstellen der Konverterkultur besteht darin, dass sie nur dann verwendet wird, wenn Sie einen Konverter haben. Erstellen Sie also einfach einen einfachen StringFormatConverter, der das Format als Parameter nimmt:

public sealed class StringFormatConverter : IValueConverter
{
    private static readonly StringFormatConverter instance = new StringFormatConverter();
    public static StringFormatConverter Instance
    {
        get
        {
            return instance;
        }
    }

    private StringFormatConverter()
    {
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return string.Format(culture, (string)parameter, value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

Dann können Sie Ihre Bindung anpassen (vorausgesetzt, Sie haben den Namespace des Konverters als "My" importiert)

<TextBlock Text="{Binding Date, Converter={x:Static my:StringFormatConverter.Instance}, ConverterCulture={x:Static glob:CultureInfo.CurrentCulture}, ConverterParameter={}{0:d}}" />

Ich verwende diesen Code mit den richtigen Ergebnissen für meine Bedürfnisse. Hoffe es könnte deine erfüllen :-)! Vielleicht werfen Sie besser eine Ausnahme, wenn Sie nicht "parieren" können. Wie du willst.

public sealed class CurrentCultureDoubleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((double)value).ToString((string)parameter ?? "0.######", CultureInfo.CurrentCulture);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double result;
        if (Double.TryParse(value as string, NumberStyles.Number, CultureInfo.CurrentCulture, out result))
        {
            return result;
        }

        throw new FormatException("Unable to convert value:" + value);
        // return value;
    }
}

Verwendungszweck:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:simulatorUi="clr-namespace:SimulatorUi"
        xmlns:Converter="clr-namespace:HQ.Wpf.Util.Converter;assembly=WpfUtil" x:Class="SimulatorUi.DlgTest"
        Title="DlgTest" Height="300" Width="300">
    <Window.DataContext>
        <simulatorUi:DlgTestModel/>
    </Window.DataContext>

    <Window.Resources>
        <Converter:CurrentCultureDoubleConverter x:Key="CurrentCultureDoubleConverter"/>
    </Window.Resources>

    <Grid>
        <TextBox Text="{Binding DoubleVal, Converter={StaticResource CurrentCultureDoubleConverter}}"/>
    </Grid>
</Window>

Ich habe mir eine Hack/Problemumgehung ausgedacht, die vermeidet, alle Ihre Bindungen zu aktualisieren. Fügen Sie diesen Code dem Konstruktor Ihres Hauptfensters hinzu.

XmlLanguage language = XmlLanguage.GetLanguage("My-Language");
typeof(XmlLanguage).GetField("_compatibleCulture", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(language, CultureInfo.CurrentCulture);
this.Language = language;

Da es Reflection verwendet, gibt es keine Garantie dafür, dass es in Zukunft funktionieren wird, aber im Moment (.NET 4.6).

Wir können einen DateTime -Konverter mit dem IvalueConverter erstellen

[ValueConversion(typeof(DateTime), typeof(String))]
    class DateTimeToLocalConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(value is DateTime)) return "Invalid DateTime";
            DateTime DateTime = (DateTime)value;
            return DateTime.ToLocalTime().ToShortDateString();

        }


        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }


    }

Wenden Sie dies in der XAML an, wie unten gezeigt

Binding="{Binding Path=createdDateTime,Converter={StaticResource DateTimeConverter}}"

Ändern Sie auch die aktuelle Kultur, um das gewünschte Format zu erhalten, und dasselbe muss für das Anwendungsstart angewendet werden

/// <summary>
        /// Set Culture
        /// </summary>
        private void SetCulture() {
            var newCulture = new CultureInfo("en-IN");
            newCulture.DateTimeFormat.ShortDatePattern = "dd-MMM-yyyy";
            newCulture.DateTimeFormat.LongDatePattern = "dd-MMM-yyyy";
            newCulture.DateTimeFormat.FullDateTimePattern = "dd-MMM-yyyy";
            CultureInfo.DefaultThreadCurrentCulture = newCulture;
            CultureInfo.DefaultThreadCurrentUICulture = newCulture;
            Thread.CurrentThread.CurrentCulture = newCulture;
            Thread.CurrentThread.CurrentUICulture = newCulture;
            FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(
                System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
        }

Wie wäre es, wenn Sie die Lanaguge im Code dahinter ändern?

this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);

Das Problem, das es vermeidet, "this.language = xmllanguage.getLanguage (Thread.currentthread.currentculture.name);" ist nicht wirklich häufig. Ich kenne keinen Benutzer hier in Frankreich, der das Datumsformat an uns oder Japan ändert, nur weil zumindest kein Benutzer weiß, dass eine solche Änderung möglich ist (und nicht weiß, wie es geht) ... also von Natürlich ist das "Sprache" nicht perfekt, aber in vielen Jahren von WPF und Silverlight -Praxis sehe ich nie ein Problem dieser Art mit jedem Benutzer ... also verwende ich immer noch den "Langage =", es ist einfach und Cover 100% der realen Bedürfnisse. Natürlich scheinen andere Lösungen besser zu sein, aber es besteht keine Notwendigkeit (und ich habe einige Implementierungen gesehen, die weit davon entfernt sind, mit "Language =" -Lösung zu vergleichen).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top