Problemi di localizzazione di StringFormat in wpf


112

In WPF 3.5SP1 utilizzo l'ultima funzionalità StringFormat in DataBindings:

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

Il problema che devo affrontare è che la data è sempre formattata in inglese ... anche se il mio sistema è in francese? Come posso forzare la data a seguire la data di sistema?


14
3 anni una domanda molto apprezzata ma nessuna risposta contrassegnata! Facce tristi tutto intorno.
Gusdor

Risposte:


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

Dalla creazione di una procedura guidata internazionalizzata in WPF


17
Sì, questo è abbastanza fastidioso. +1
Szymon Rozga

2
Grazie per aver risolto il mio mal di testa.
Skurmedel

9
Grande. Ma cosa fare se la cultura cambia durante il ciclo di vita dell'applicazione (ad esempio, l'utente può cambiare la sua cultura preferita in una finestra di dialogo delle impostazioni). Secondo la documentazione, FrameworkElement.LanguageProperty.OverrideMetadata non può essere chiamato più di una volta (genera un'eccezione)
TJKjaer

1
@pengibot Questa soluzione funziona per me. Sto usando .net 4 / C # / WPF e ho inserito il codice nel metodo OnStartup.
Björn

18
Nota che l' elemento Run non eredita da FrameworkElement , quindi se leghi date ecc. A un Run, avrai bisogno di una chiamata extra per typeof (System.Windows.Documents.Run)
Mat Fergusson

90

Definisci il seguente spazio dei nomi xml:

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

Ora guarda questa fantastica soluzione:

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

Sono ben consapevole che questa non è una soluzione globale e la richiederai su ciascuno dei tuoi binding, ma sicuramente è solo un buon XAML? Per quanto ne so, la prossima volta che il binding si aggiornerà utilizzerà quello corretto CultureInfo.CurrentCultureo quello che hai fornito.

Questa soluzione aggiornerà immediatamente i tuoi binding con i valori corretti, ma sembra un sacco di codice per qualcosa di così raro e innocuo.


4
Eccellente! Ha funzionato meravigliosamente! Non ho problemi ad aggiungerlo ai pochi posti in cui è necessario. A proposito, nel tuo esempio manca un}
Johncl

3
Lavoro eccellente. È così strano che WPF utilizzi l'inglese americano per impostazione predefinita, al contrario della cultura corrente.
Kris Adams

12

Volevo solo aggiungere che la risposta di Loraderon funziona alla grande nella maggior parte dei casi. Quando inserisco la seguente riga di codice nel mio App.xaml.cs, le date nei miei TextBlock sono formattate nella lingua corretta.

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

Dico `` la maggior parte dei casi ''. Ad esempio, questo funzionerà immediatamente:

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

... ma quando si utilizza Run's in un TextBlock, DateTime è formattato nella lingua predefinita.

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

Perché questo funzionasse, avevo bisogno della risposta di Gusdor , ovvero l'aggiunta di ConverterCulture = {x: Static gl: CultureInfo.CurrentCulture} al Binding.

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

Spero che questa risposta aggiuntiva possa essere utile a qualcuno.


In effetti, Run non deriva da FrameworkElement. Potresti provare a modificare la risposta di loraderon per ripetere il suo codice per la base di Run (FrameworkContentElement) e per FrameworkElement.
Nathan Phillips

Per coloro che potrebbero chiedersi: xmlns: gl = "clr-namespace: System.Globalization; assembly = mscorlib"
Igor Meszaros

11

Basta inserire la scorciatoia per la cultura nel tag di primo livello:

xml:lang="de-DE"

per esempio:

<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
Ma questo è altrettanto negativo quanto presumere che en-US sia la cultura "corretta". Dovrebbe piuttosto prendere le impostazioni dalla macchina dell'utente.
nome improprio

Grazie mille, questo era esattamente quello che stavo cercando! Se WPF pensa che en-EN sia la cultura corretta per ogni situazione, posso farlo anch'io con la mia localizzazione. Dato che sto lavorando a un'applicazione proof-of-concept in cui la velocità di sviluppo è all'ordine del giorno, non c'è tempo per scherzare con dozzine di righe di codice solo per ottenere una singola DatePickerper fare il suo lavoro, quindi questa semplice soluzione ha ottenuto mi rimetto rapidamente in carreggiata!
M463

migliore risposta per il mio caso, finalmente ho cercato per anni :) e ovviamente è corretto, o
presumi

10

Come già affermato, XAML utilizza per impostazione predefinita le impostazioni cultura invarianti (en-US) e puoi usare

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

per impostare le impostazioni cultura predefinite per la lingua delle impostazioni cultura correnti. Ma il commento è sbagliato; questo non utilizza la cultura corrente, poiché non vedrai alcuna personalizzazione che l'utente potrebbe aver fatto, sarà sempre l'impostazione predefinita per la lingua.

Per utilizzare effettivamente la cultura corrente con le personalizzazioni, sarà necessario impostare ConverterCultureinsieme a StringFormat, come in

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

con il gldefinito come uno spazio dei nomi globale nel tuo elemento root

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

Se lo fai tramite codice anziché XAML, è il seguente:binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Metalogic

8

Se hai bisogno di cambiare la lingua mentre il programma è in esecuzione, puoi semplicemente cambiare la proprietà Language sul tuo elemento radice (non sono sicuro se questo ha un effetto immediato o se il sottoelemento deve essere ricreato, nel mio caso funziona almeno)

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

si rivaluta immediatamente ma purtroppo deve essere impostato per ogni stanza (finestra) separata
Firo

6

Il codice completo per cambiare la localizzazione anche in elementi come <Run />questo è questo:

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

Se vuoi cambiare le informazioni sulla cultura in fase di esecuzione, puoi usare un comportamento (vedi sotto)

  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

Se stai lavorando sul codice anziché su XAML, puoi impostare ConverterCulture come segue:

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

Complimenti a @KZeise per aver sottolineato la sottile differenza tra l'utilizzo della definizione di cultura predefinita e l'utilizzo della definizione di cultura personalizzata dell'utente.


-3

Usa Label (inclusa Cultture) e non texblock

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.