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?

Pavel Anikhouski
sumber
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

loraderon
sumber
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.

Gusdor
sumber
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.

Daniël Teunkens
sumber
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>
Gerrit Horeis
sumber
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"
KZeise
sumber
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);
Peter
sumber
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
habakuk
sumber
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();
    }
}
pengguna3173620
sumber
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.

Metalogic
sumber
-3

Gunakan Label (termasuk Cultture) dan bukan texblock

David
sumber