web-dev-qa-db-fra.com

Utilisez "réel" CultureInfo.CurrentCulture dans WPF Binding, pas CultureInfo à partir de IetfLanguageTag

Dans mon cas:

J'ai un TextBlock Binding à une propriété de type DateTime . Je veux qu'il soit affiché comme le dit les paramètres régionaux de l'utilisateur.

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

Je configure la propriété Language comme WPF XAML Bindings et CurrentCulture Display Indique:

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

Mais avec cette ligne de code, il affiche simplement le texte en tant que format par défaut de CultureInfo Avec IetfLanguageTag de CurrentCulture, et non pas comme l'indique la valeur effective sélectionnée dans les paramètres de région système:

(par exemple, pour "de-DE" jj.MM.yyyy est utilisé à la place de aaaa-MM-jj)

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

Existe-t-il un moyen permettant à Binding d'utiliser le format correct sans définir ConverterCulture sur chaque liaison?

Dans du code

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

utilise les bons paramètres de culture.

modifier:

une autre façon qui ne fonctionne pas comme souhaité (comme this.Language = ... do):

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

et

<Binding Source="{x:Static glob:CultureInfo.CurrentCulture}" 
 Path="IetfLanguageTag" 
 ConverterCulture="{x:Static glob:CultureInfo.InvariantCulture}" />
36
Markus k

Vous pouvez créer une sous-classe de liaison (par exemple, CultureAwareBinding) qui définit automatiquement ConverterCulture sur la culture actuelle lors de sa création.

Ce n'est pas une solution parfaite, mais c'est probablement la seule, car obliger rétroactivement Binding à respecter la culture pourrait casser d'autres codes de WPF qui dépendent de ce comportement.

Faites-moi savoir si vous avez besoin de plus d'aide!

26
aKzenT

Ceci est une extension de la réponse de aKzenT. Ils ont proposé de créer une sous-classe de la classe Binding et de définir ConverterCulture en CurrentCulture. Même si la réponse est très simple, je pense que certaines personnes peuvent ne pas être très à l'aise pour la mettre en œuvre. Je partage donc la version de code de la réponse de aKzenT avec un exemple d'utilisation en XAML. 

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

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

Exemple d'utilisation de ceci en XAML

1) Vous devez importer votre espace de noms dans votre fichier XAML:

<Page
    ...
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:myWpfLib="clr-namespace:MyWpfLibrary;Assembly=<Assembly_name>"
    ...
>

2) Utilisation dans le monde réel de CultureAwareBinding

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

Mettez la ligne de code suivante, avant toute interface utilisateur est initialisée. Cela a fonctionné pour moi.

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

(Et supprimez tous les paramètres de culture explicites)

5
Alan Hauge

Votre deuxième tentative a été proche et m'a conduit à une solution qui fonctionne pour moi.

Le problème avec la définition de ConverterCulture est qu’il n’est utilisé que lorsque vous disposez d’un convertisseur. Donc, créez simplement un StringFormatConverter simple qui prend le format en tant que paramètre:

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();
    }
}

Ensuite, vous pouvez ajuster votre liaison (en supposant que vous ayez importé l’espace de nom du convertisseur en tant que "mon")

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

J'utilise ce code avec des résultats appropriés à mes besoins. J'espère que cela pourrait remplir votre :-)! Dépend de vous.

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;
    }
}

Usage:

<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>
2
Eric Ouellet

J'ai mis au point une solution de contournement qui évite de mettre à jour toutes vos liaisons. Ajoutez ce code au constructeur de votre fenêtre principale.

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

Puisqu'il utilise la réflexion, rien ne garantit que cela fonctionnera à l'avenir, mais pour l'instant, c'est le cas (.NET 4.6).

2
Joost van den Boom

Nous pouvons créer un convertisseur DateTime en utilisant IValueConverter

[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();
        }


    }

Appliquez ceci dans le XAML comme indiqué ci-dessous

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

Modifiez également la culture actuelle pour obtenir le format souhaité. Le même logiciel doit être appliqué au démarrage de l'application.

/// <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)));
        }
0
ASHOK MANGHAT