Masalah Lokalisasi StringFormat di wpf


112

Di WPF 3.5SP1 saya menggunakan fitur terakhir StringFormat di DataBindings:

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

Masalah yang saya hadapi adalah tanggal selalu diformat dalam bahasa Inggris ... meskipun sistem saya dalam bahasa Prancis? Bagaimana saya bisa memaksa tanggal untuk mengikuti tanggal sistem?


14
3 tahun pertanyaan berperingkat tinggi tetapi tidak ada jawaban yang ditandai! Semua wajah sedih.
Gusdor

Jawaban:


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

Dari Membuat Wizard Internasionalisasi di WPF


17
Ya, ini cukup mengganggu. +1
Szymon Rozga

2
Terima kasih telah mengatasi sakit kepala saya.
Skurmedel

9
Bagus. Tetapi apa yang harus dilakukan jika budaya berubah selama siklus hidup aplikasi (misalnya, pengguna dapat mengubah budaya pilihannya dalam dialog pengaturan). Menurut dokumentasi FrameworkElement.LanguageProperty.OverrideMetadata tidak dapat dipanggil lebih dari sekali (ini melontarkan pengecualian)
TJKjaer

1
@pengibot Solusi ini bekerja untuk saya. Saya menggunakan .net 4 / C # / WPF dan saya memasukkan kode ke metode OnStartup.
Björn

18
Perhatikan bahwa elemen Run tidak mewarisi dari FrameworkElement , jadi jika Anda mengikat tanggal dll ke Run maka Anda akan memerlukan panggilan tambahan untuk typeof (System.Windows.Documents.Run)
Mat Fergusson

90

Tentukan namespace xml berikut:

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

Sekarang lihatlah perbaikan fantastis ini:

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

Saya sangat sadar ini bukan perbaikan global dan Anda akan membutuhkannya di setiap Bindings Anda, tetapi tentunya itu hanya XAML yang bagus? Sejauh yang saya ketahui, saat berikutnya pembaruan yang mengikat itu akan menggunakan yang benar CultureInfo.CurrentCultureatau apa pun yang Anda berikan.

Solusi ini akan segera memperbarui Bindings Anda dengan nilai yang benar tetapi sepertinya banyak kode untuk sesuatu yang sangat langka dan tidak berbahaya.


4
Luar biasa! Ini bekerja dengan sangat baik! Saya tidak punya masalah menambahkan ini ke beberapa tempat yang dibutuhkan. Btw contoh Anda hilang a}
Johncl

3
Kerja bagus. Sangat aneh bahwa WPF menggunakan bahasa Inggris-AS secara default, yang bertentangan dengan budaya saat ini.
Kris Adams

12

Saya hanya ingin menambahkan bahwa jawaban loraderon bekerja dengan baik dalam banyak kasus. Ketika saya meletakkan baris kode berikut di App.xaml.cs saya, tanggal di TextBlocks saya diformat dalam budaya yang benar.

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

Saya mengatakan 'kebanyakan kasus'. Misalnya, ini akan berhasil di luar kotak:

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

... tetapi saat menggunakan Run di TextBlock, DateTime diformat dalam budaya default.

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

Agar ini berhasil, saya membutuhkan jawaban Gusdor , yaitu menambahkan ConverterCulture = {x: Static gl: CultureInfo.CurrentCulture} ke 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)

Saya berharap jawaban tambahan ini akan berguna bagi seseorang.


Memang, Run tidak berasal dari FrameworkElement. Anda dapat mencoba memodifikasi jawaban loraderon untuk mengulangi kodenya untuk basis Run (FrameworkContentElement) serta untuk FrameworkElement.
Nathan Phillips

Bagi mereka yang mungkin bertanya-tanya: xmlns: gl = "clr-namespace: System.Globalization; assembly = mscorlib"
Igor Meszaros

11

Cukup masukkan pintasan budaya ke tag tingkat atas:

xml:lang="de-DE"

misalnya:

<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
Tapi ini sama buruknya dengan asumsi bahwa en-US adalah budaya 'Benar'. Ini lebih baik mengambil pengaturan dari mesin pengguna.
keliru

Terima kasih banyak, inilah yang saya cari! Jika WPF berpikir bahwa en-EN adalah budaya yang benar untuk situasi apa pun, saya juga bisa dengan lokalisasi saya sendiri. Saat saya mengerjakan aplikasi bukti konsep di mana kecepatan pengembangan adalah urutan hari ini, tidak ada waktu untuk bermain-main dengan lusinan baris kode hanya untuk mendapatkan satu DatePickeruntuk melakukan tugasnya, jadi perbaikan mudah ini didapat saya cepat kembali ke jalur!
M463

jawaban terbaik untuk kasus saya, akhirnya mencari berabad-abad :) dan tentu saja itu benar, baik Anda menganggap en-US atau de-DE ... orang selalu memiliki masalah dengan solusi sederhana -.-
MushyPeas

10

Seperti yang telah disebutkan, XAML default ke budaya invarian (en-US), dan Anda dapat menggunakan

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

untuk mengatur budaya ke budaya default untuk bahasa budaya saat ini. Tapi komentar itu salah; ini tidak menggunakan budaya saat ini, karena Anda tidak akan melihat penyesuaian apa pun yang mungkin dibuat pengguna, itu akan selalu menjadi default untuk bahasa tersebut.

Untuk benar-benar menggunakan budaya saat ini dengan kustomisasi, Anda perlu mengatur ConverterCulturebersama dengan StringFormat, seperti pada

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

dengan yang glditentukan sebagai namespace global di elemen root Anda

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

Jika Anda melakukan ini melalui kode alih-alih XAML itu sebagai berikut:binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Metalogic

8

Jika Anda perlu mengubah bahasa saat program berjalan, Anda bisa mengubah properti Bahasa pada elemen root Anda (saya tidak yakin apakah ini memiliki efek instan atau jika sub elemen harus dibuat ulang, dalam kasus saya ini setidaknya berfungsi)

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

itu segera mengevaluasi kembali tetapi sayangnya harus diatur untuk setiap rootelement (jendela) terpisah
Firo

6

Kode lengkap untuk mengganti pelokalan juga dalam elemen seperti <Run />ini:

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

Jika Anda ingin mengubah info budaya saat runtime, Anda dapat menggunakan perilaku (lihat di bawah)

  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

Jika Anda mengerjakan kode daripada XAML, Anda dapat mengatur ConverterCulture sebagai berikut:

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

Kudos to @KZeise karena menunjukkan perbedaan halus antara menggunakan definisi budaya default dan menggunakan definisi budaya kustom pengguna.


-3

Gunakan Label (termasuk Cultture) dan bukan texblock

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.