ปัญหา StringFormat Localization ใน wpf


112

ใน WPF 3.5SP1 ฉันใช้คุณลักษณะสุดท้าย StringFormat ใน DataBindings:

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

ปัญหาที่ฉันพบคือวันที่จะถูกจัดรูปแบบเป็นภาษาอังกฤษเสมอ ... แม้ว่าระบบของฉันจะเป็นภาษาฝรั่งเศส? ฉันจะบังคับให้วันที่เป็นไปตามวันที่ของระบบได้อย่างไร?


14
3 ปีเป็นคำถามที่ได้คะแนนสูง แต่ไม่มีคำตอบที่ทำเครื่องหมายไว้! หน้าเศร้าทุกรอบ
Gusdor

คำตอบ:


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

จากการสร้าง Internationalized Wizard ใน WPF


17
นี่มันค่อนข้างน่ารำคาญ +1
Szymon Rozga

2
ขอบคุณสำหรับการแก้ไขอาการปวดหัวของฉัน
Skurmedel

9
ยิ่งใหญ่ แต่จะทำอย่างไรถ้าวัฒนธรรมเปลี่ยนไปในระหว่างวงจรชีวิตของแอปพลิเคชัน (เช่นผู้ใช้สามารถเปลี่ยนวัฒนธรรมที่ต้องการได้ในกล่องโต้ตอบการตั้งค่า) ตามเอกสาร FrameworkElement.LanguageProperty.OverrideMetadata ไม่สามารถเรียกได้มากกว่าหนึ่งครั้ง (จะมีข้อยกเว้น)
TJKjaer

1
@pengibot วิธีนี้ใช้ได้กับฉัน ฉันใช้. net 4 / C # / WPF และฉันใส่รหัสในวิธี OnStartup
Björn

18
โปรดทราบว่าองค์ประกอบRunไม่ได้สืบทอดมาจากFrameworkElementดังนั้นหากคุณผูกวันที่ ฯลฯ เข้ากับRunคุณจะต้องมีการเรียกพิเศษสำหรับtypeof (System.Windows.Documents.Run)
Mat Fergusson

90

กำหนดเนมสเปซ xml ต่อไปนี้:

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

ตอนนี้ดูการแก้ไขที่ยอดเยี่ยมนี้:

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

ฉันทราบดีว่านี่ไม่ใช่การแก้ไขระดับโลกและคุณจะต้องใช้มันในการผูกแต่ละครั้ง แต่นั่นเป็น XAML ที่ดีอย่างแน่นอน? เท่าที่ฉันทราบในครั้งต่อไปการอัปเดตการเชื่อมโยงจะใช้สิ่งที่ถูกต้องCultureInfo.CurrentCultureหรือสิ่งที่คุณให้มา

โซลูชันนี้จะอัปเดตการเชื่อมโยงของคุณทันทีด้วยค่าที่ถูกต้องแต่ดูเหมือนว่าจะมีโค้ดจำนวนมากสำหรับสิ่งที่หายากและไม่มีพิษภัย


4
ยอดเยี่ยม สิ่งนี้ได้ผลอย่างยอดเยี่ยม! ฉันไม่มีปัญหาในการเพิ่มสิ่งนี้ไปยังสถานที่ไม่กี่แห่งที่จำเป็น Btw ตัวอย่างของคุณไม่มี a}
Johncl

3
ทำงานได้ดีเยี่ยม เป็นเรื่องแปลกมากที่ WPF ใช้ US-English โดยค่าเริ่มต้นเมื่อเทียบกับวัฒนธรรมปัจจุบัน
Kris Adams

12

ฉันแค่อยากจะเพิ่มว่าคำตอบของloraderon ใช้งานได้ดีในกรณีส่วนใหญ่ เมื่อฉันใส่โค้ดบรรทัดต่อไปนี้ใน App.xaml.cs วันที่ใน TextBlocks ของฉันจะถูกจัดรูปแบบตามวัฒนธรรมที่ถูกต้อง

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

ฉันพูดว่า 'กรณีส่วนใหญ่' ตัวอย่างเช่นสิ่งนี้จะได้ผล:

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

... แต่เมื่อใช้ Run ใน TextBlock DateTime จะถูกจัดรูปแบบในวัฒนธรรมเริ่มต้น

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

เพื่อให้ได้ผลฉันต้องการคำตอบของGusdorคือการเพิ่ม ConverterCulture = {x: Static gl: CultureInfo.CurrentCulture} ใน 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)

ฉันหวังว่าคำตอบเพิ่มเติมนี้จะเป็นประโยชน์กับใครบางคน


แท้จริงแล้ว Run ไม่ได้มาจาก FrameworkElement คุณสามารถลองแก้ไขคำตอบของ loraderon เพื่อทำโค้ดซ้ำสำหรับฐานของ Run (FrameworkContentElement) เช่นเดียวกับ FrameworkElement
Nathan Phillips

สำหรับผู้ที่อาจสงสัย: xmlns: gl = "clr-namespace: System.Globalization; assembly = mscorlib"
Igor Meszaros

11

เพียงใส่ทางลัดวัฒนธรรมลงในแท็กระดับบนสุด:

xml:lang="de-DE"

เช่น:

<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
แต่นี่ก็แย่พอ ๆ กับการสมมติว่า en-US เป็นวัฒนธรรมที่ 'ถูกต้อง' ควรใช้การตั้งค่าจากเครื่องของผู้ใช้
เรียกชื่อผิด

ขอบคุณมากนี่คือสิ่งที่ฉันกำลังมองหา! ถ้า WPF คิดว่า en-EN เป็นวัฒนธรรมที่ถูกต้องสำหรับสถานการณ์ใด ๆ ฉันก็สามารถแปลภาษาของตัวเองได้ ในขณะที่ฉันกำลังทำงานกับแอปพลิเคชันพิสูจน์แนวคิดซึ่งความเร็วในการพัฒนาเป็นลำดับของวันจึงไม่มีเวลายุ่งกับโค้ดหลายสิบบรรทัดเพียงเพื่อให้ได้งานเดียวDatePickerดังนั้นการแก้ไขที่ง่ายนี้จึงมีขึ้น ฉันรีบกลับไปติดตาม!
M463

คำตอบที่ดีที่สุดสำหรับกรณีของฉันในที่สุดก็มองหาอายุ :) และแน่นอนว่ามันถูกต้องไม่ว่าคุณจะเป็น en-US หรือ de-DE ... คนมักมีปัญหากับวิธีแก้ปัญหาง่ายๆ -.-
MushyPeas

10

ตามที่ระบุไว้แล้ว XAML มีค่าเริ่มต้นเป็นวัฒนธรรมที่ไม่แปรเปลี่ยน (en-US) และคุณสามารถใช้ได้

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

เพื่อตั้งค่าวัฒนธรรมเป็นวัฒนธรรมเริ่มต้นสำหรับภาษาของวัฒนธรรมปัจจุบัน แต่ความคิดเห็นผิด; สิ่งนี้ไม่ได้ใช้วัฒนธรรมปัจจุบันเนื่องจากคุณจะไม่เห็นการปรับแต่งใด ๆ ที่ผู้ใช้อาจทำขึ้นมันจะเป็นค่าเริ่มต้นสำหรับภาษาเสมอ

หากต้องการใช้วัฒนธรรมปัจจุบันกับการปรับแต่งจริงคุณจะต้องตั้งค่าConverterCultureร่วมกับวัฒนธรรมStringFormatในรูปแบบ

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

ด้วยการglกำหนดเป็นเนมสเปซส่วนกลางในองค์ประกอบรากของคุณ

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

หากคุณทำสิ่งนี้ผ่านรหัสแทน XAML จะเป็นดังนี้:binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Metalogic

8

หากคุณต้องการเปลี่ยนภาษาในขณะที่โปรแกรมกำลังทำงานอยู่คุณก็สามารถเปลี่ยนคุณสมบัติภาษาในองค์ประกอบรากของคุณได้ (ฉันไม่แน่ใจว่าสิ่งนี้มีผลทันทีหรือต้องสร้างองค์ประกอบย่อยใหม่ในกรณีของฉันอย่างน้อยก็ใช้ได้)

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

มันประเมินใหม่ทันที แต่น่าเศร้าที่ต้องตั้งค่าสำหรับแต่ละรูทเมนต์ (หน้าต่าง) แยกออกจากกัน
Firo

6

รหัสเต็มเพื่อเปลี่ยนการแปลเป็นภาษาท้องถิ่นในองค์ประกอบเช่น<Run />นี้:

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

หากคุณต้องการเปลี่ยนข้อมูลวัฒนธรรมในขณะรันไทม์คุณสามารถใช้ลักษณะการทำงาน (ดูด้านล่าง)

  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

หากคุณกำลังทำงานกับโค้ดมากกว่า XAML คุณสามารถตั้งค่า ConverterCulture ได้ดังนี้:

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

ขอชื่นชม @KZeise เพื่อชี้ให้เห็นความแตกต่างเล็กน้อยระหว่างการใช้นิยามวัฒนธรรมเริ่มต้นกับการใช้นิยามวัฒนธรรมที่กำหนดเองของผู้ใช้


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.