Problèmes de localisation StringFormat dans wpf

112

Dans WPF 3.5SP1, j'utilise la dernière fonctionnalité StringFormat dans DataBindings:

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

Le problème auquel je suis confronté est que la date est toujours formatée en anglais ... bien que mon système soit en français? Comment puis-je forcer la date à suivre la date du système?

Pavel Anikhouski
la source
14
3 ans une question hautement cotée mais aucune réponse marquée! Des visages tristes tout autour.
Gusdor

Réponses:

212
// 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)));

À partir de la création d'un assistant internationalisé dans WPF

Loraderon
la source
17
Oui, c'est assez ennuyeux. +1
Szymon Rozga
2
Merci d'avoir résolu mon mal de tête.
Skurmedel
9
Génial. Mais que faire si la culture change pendant le cycle de vie de l'application (par exemple, l'utilisateur peut changer sa culture préférée dans une boîte de dialogue de paramètres). Selon la documentation FrameworkElement.LanguageProperty.OverrideMetadata ne peut pas être appelé plus d'une fois (il lève une exception)
TJKjaer
1
@pengibot Cette solution fonctionne pour moi. J'utilise .net 4 / C # / WPF et je mets le code dans la méthode OnStartup.
Björn
18
Notez que l' élément Run n'hérite pas de FrameworkElement , donc si vous liez des dates, etc. à un Run, vous aurez besoin d'un appel supplémentaire pour typeof (System.Windows.Documents.Run)
Mat Fergusson
90

Définissez l'espace de noms XML suivant:

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

Maintenant, voici ce correctif fantastique:

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

Je suis bien conscient que ce n'est pas un correctif global et vous en aurez besoin sur chacune de vos liaisons, mais c'est sûrement juste du bon XAML? Pour autant que je sache, la prochaine fois que la liaison sera mise à jour, elle utilisera le correct CultureInfo.CurrentCultureou ce que vous avez fourni.

Cette solution mettra immédiatement à jour vos liaisons avec les valeurs correctes, mais cela semble être beaucoup de code pour quelque chose d'aussi rare et inoffensif.

Gusdor
la source
4
Excellent! Cela a fonctionné à merveille! Je n'ai aucun problème à ajouter cela aux quelques endroits où c'est nécessaire. Btw votre exemple manque un}
Johncl
3
Excellent travail. C'est tellement étrange que WPF utilise l'anglais américain par défaut, par opposition à la culture actuelle.
Kris Adams
12

Je voulais juste ajouter que la réponse de Loraderon fonctionne très bien dans la plupart des cas. Lorsque je mets la ligne de code suivante dans mon App.xaml.cs, les dates de mes TextBlocks sont formatées dans la culture correcte.

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

Je dis `` la plupart des cas '', par exemple, cela fonctionnera immédiatement:

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

... mais lors de l'utilisation de Run dans un TextBlock, le DateTime est formaté dans la culture par défaut.

<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")

Pour que cela fonctionne, j'avais besoin de la réponse de Gusdor , à savoir ajouter ConverterCulture = {x: Static gl: CultureInfo.CurrentCulture} à la liaison.

<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)

J'espère que cette réponse supplémentaire sera utile à quelqu'un.

Daniël Teunkens
la source
En effet, Run ne dérive pas de FrameworkElement. Vous pouvez essayer de modifier la réponse de loraderon pour répéter son code pour la base de Run (FrameworkContentElement) ainsi que pour FrameworkElement.
Nathan Phillips
Pour ceux qui pourraient se demander: xmlns: gl = "clr-namespace: System.Globalization; assembly = mscorlib"
Igor Meszaros
11

Insérez simplement le raccourci de culture vers la balise de niveau supérieur:

xml:lang="de-DE"

par exemple:

<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>
Gerrit Horeis
la source
5
Mais c'est tout aussi mauvais que de supposer que en-US est la culture «correcte». Il devrait plutôt prendre les paramètres de la machine de l'utilisateur.
terme impropre
Merci beaucoup, c'était exactement ce que je cherchais! Si WPF pense que en-EN est la culture appropriée pour n'importe quelle situation, je le peux aussi avec ma propre localisation. Alors que je travaille sur une application de preuve de concept où la vitesse de développement est à l'ordre du jour, il n'y a pas de temps pour jouer avec des dizaines de lignes de code juste pour en obtenir une seule DatePickerpour faire son travail, donc cette solution facile a obtenu me remettre rapidement sur les rails!
M463
meilleure réponse pour mon cas, enfin cherché depuis des lustres :) et bien sûr c'est correct, soit vous supposez que c'est en-US ou c'est de-DE ... les gens ont toujours des problèmes avec des solutions simples -.-
MushyPeas
10

Comme déjà indiqué, XAML utilise par défaut la culture invariante (en-US), et vous pouvez utiliser

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

pour définir la culture sur la culture par défaut pour la langue de la culture actuelle. Mais le commentaire est faux; cela n'utilise pas la culture actuelle, car vous ne verrez aucune personnalisation que l'utilisateur aurait pu faire, ce sera toujours la valeur par défaut pour la langue.

Pour utiliser réellement la culture actuelle avec des personnalisations, vous devrez définir le ConverterCultureavec le StringFormat, comme dans

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

avec le gldéfini comme un espace de noms global dans votre élément racine

xmlns:gl="clr-namespace:System.Globalization;assembly=mscorlib"
KZeise
la source
Si vous faites cela via du code au lieu de XAML, c'est comme suit:binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Metalogic
8

Si vous avez besoin de changer la langue pendant que le programme est en cours d'exécution, vous pouvez simplement changer la propriété Language sur votre élément racine (je ne sais pas si cela a un effet instantané ou si le sous-élément doit être recréé, dans mon cas, cela fonctionne au moins)

element.Language = System.Windows.Markup.XmlLanguage.GetLanguage(culture.IetfLanguageTag);
Peter
la source
il réévalue immédiatement mais doit malheureusement être défini pour chaque élément racine (fenêtre) séparé
Firo
6

Le code complet pour basculer la localisation également dans des éléments comme celui <Run />-ci:

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
habakuk
la source
0

Si vous souhaitez modifier les informations de culture au moment de l'exécution, vous pouvez utiliser un comportement (voir ci-dessous)

  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();
    }
}
user3173620
la source
0

Si vous travaillez sur du code plutôt que sur XAML, vous pouvez définir le ConverterCulture comme suit:

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

Félicitations à @KZeise pour avoir souligné la différence subtile entre l'utilisation de la définition de culture par défaut et l'utilisation de la définition de culture personnalisée de l'utilisateur.

Metalogic
la source
-3

Utilisez Label (y compris Cultture) et non texblock

David
la source