Vấn đề bản địa hóa StringFormat trong wpf


112

Trong WPF 3.5SP1, tôi sử dụng tính năng cuối cùng StringFormat trong DataBindings:

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

Vấn đề tôi gặp phải là ngày luôn được định dạng bằng tiếng Anh ... mặc dù hệ thống của tôi là tiếng Pháp? Làm thế nào tôi có thể buộc ngày theo ngày hệ thống?


14
3 năm một câu hỏi được đánh giá cao nhưng không có câu trả lời được đánh dấu! Những khuôn mặt buồn rười rượi.
Gusdor

Câu trả lời:


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

Từ việc tạo một trình hướng dẫn quốc tế hóa trong WPF


17
Đúng là điều này khá khó chịu. +1
Szymon Rozga

2
Cảm ơn bạn đã giải quyết cơn đau đầu của tôi.
Skurmedel

9
Tuyệt quá. Nhưng phải làm gì nếu văn hóa thay đổi trong vòng đời của ứng dụng (ví dụ: người dùng có thể thay đổi văn hóa ưa thích của mình trong hộp thoại cài đặt). Theo tài liệu FrameworkElement.LanguageProperty.OverrideMetadata không thể được gọi nhiều hơn một lần (nó ném một ngoại lệ)
TJKjaer

1
@pengibot Giải pháp này phù hợp với tôi. Tôi đang sử dụng .net 4 / C # / WPF và tôi đặt mã trong phương thức OnStartup.
Björn

18
Lưu ý rằng Run yếu tố không kế thừa từ FrameworkElement , vì vậy nếu bạn ràng buộc ngày vv để một Run sau đó bạn sẽ cần một cuộc gọi thêm cho typeof (System.Windows.Documents.Run)
Mat Fergusson

90

Xác định không gian tên xml sau:

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

Bây giờ hãy xem bản sửa lỗi tuyệt vời này:

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

Tôi biết rõ đây không phải là một bản sửa lỗi toàn cầu và bạn sẽ yêu cầu nó trên từng Binding của mình nhưng chắc chắn đó chỉ là XAML tốt? Theo như tôi được biết, lần sau khi cập nhật ràng buộc, nó sẽ sử dụng đúng CultureInfo.CurrentCulturehoặc bất cứ thứ gì bạn đã cung cấp.

Giải pháp này sẽ ngay lập tức cập nhật Bindings của bạn với các giá trị chính xác nhưng có vẻ như rất nhiều mã cho một thứ quá hiếm và vô hại.


4
Thông minh! Điều này hoạt động tuyệt vời! Tôi không có vấn đề gì khi thêm nó vào một vài nơi cần thiết. Btw ví dụ của bạn bị thiếu a}
Johncl 13/12/11

3
Công việc xuất sắc. Thật kỳ lạ khi WPF sử dụng tiếng Anh-Mỹ theo mặc định, trái ngược với văn hóa hiện tại.
Kris Adams

12

Tôi chỉ muốn nói thêm rằng câu trả lời của loraderon hoạt động tuyệt vời trong hầu hết các trường hợp. Khi tôi đặt dòng mã sau vào App.xaml.cs, ngày tháng trong TextBlock của tôi được định dạng theo đúng văn hóa.

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

Tôi nói 'hầu hết các trường hợp'. Ví dụ, điều này sẽ hoạt động tốt:

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

... nhưng khi sử dụng Run trong TextBlock, DateTime được định dạng theo văn hóa mặc định.

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

Để điều này hoạt động, tôi cần câu trả lời của Gusdor , cụ thể là thêm ConverterCulture = {x: Static gl: CultureInfo.CurrentCulture} vào 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)

Tôi hy vọng câu trả lời bổ sung này sẽ có ích cho ai đó.


Thật vậy, Run không bắt nguồn từ FrameworkElement. Bạn có thể thử sửa đổi câu trả lời của loraderon để lặp lại mã của anh ấy cho cơ sở của Run (FrameworkContentElement) cũng như cho FrameworkElement.
Nathan Phillips

Đối với những người có thể thắc mắc: xmlns: gl = "clr-namespace: System.Globalization; lắp ráp = mscorlib"
Igor Mészáros

11

Chỉ cần chèn lối tắt văn hóa vào thẻ cấp cao nhất:

xml:lang="de-DE"

ví dụ:

<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
Nhưng điều này cũng tệ khi cho rằng en-US là văn hóa 'Đúng đắn'. Nó nên lấy các cài đặt từ máy của người dùng.
misnomer

Cảm ơn bạn rất nhiều, đây chính xác là những gì tôi đang tìm kiếm! Nếu WPF nghĩ rằng en-EN là văn hóa chính xác cho mọi tình huống, thì tôi cũng có thể tự bản địa hóa của mình. Vì tôi đang làm việc trên một ứng dụng bằng chứng khái niệm trong đó tốc độ phát triển là thứ tự trong ngày, không có thời gian để lộn xộn với hàng tá dòng mã chỉ để thực hiện một công việc duy nhất DatePicker, vì vậy, cách khắc phục dễ dàng này đã tôi nhanh chóng trở lại theo dõi!
M463

Câu trả lời tốt nhất cho trường hợp của tôi, cuối cùng đã được tìm kiếm cho các lứa tuổi :) và tất nhiên đó là đúng, hoặc là bạn giả định của nó en-US hoặc đó là de-DE ... người luôn luôn có vấn đề với giải pháp đơn giản -.-
MushyPeas

10

Như đã nêu, XAML mặc định là văn hóa bất biến (en-US) và bạn có thể sử dụng

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

để đặt văn hóa thành văn hóa mặc định cho ngôn ngữ của văn hóa hiện tại. Nhưng nhận xét là sai; điều này không sử dụng văn hóa hiện tại, vì bạn sẽ không thấy bất kỳ tùy chỉnh nào mà người dùng có thể đã thực hiện, nó sẽ luôn là mặc định cho ngôn ngữ.

Để thực sự sử dụng văn hóa hiện tại với các tùy chỉnh, bạn sẽ cần phải thiết lập các tùy chỉnh ConverterCulturecùng với StringFormat, như trong

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

với glđịnh nghĩa là không gian tên chung trong phần tử gốc của bạn

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

Nếu bạn đang làm điều này thông qua mã thay vì XAML nó như sau:binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Metalogic

8

Nếu bạn cần thay đổi ngôn ngữ trong khi chương trình đang chạy, bạn chỉ có thể thay đổi thuộc tính Ngôn ngữ trên phần tử gốc của mình (tôi không chắc liệu điều này có tác dụng tức thì hay phần tử phụ phải được tạo lại, trong trường hợp của tôi, điều này ít nhất cũng hoạt động)

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

nó lập tức đánh giá lại nhưng thật đáng buồn này phải được thiết lập cho mỗi và mọi rootelement (cửa sổ) riêng biệt
Firo

6

Mã đầy đủ để chuyển đổi bản địa hóa cũng trong các phần tử như <Run />sau:

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

Nếu bạn muốn thay đổi thông tin văn hóa trong thời gian chạy, bạn có thể sử dụng một hành vi (xem bên dưới)

  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

Nếu bạn đang làm việc trên mã thay vì XAML, bạn có thể đặt ConverterCulture như sau:

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

Kudos cho @KZeise vì đã chỉ ra sự khác biệt nhỏ giữa việc sử dụng định nghĩa văn hóa mặc định và sử dụng định nghĩa văn hóa tùy chỉnh của người dùng.


-3

Sử dụng Nhãn (bao gồm cả Cultture) chứ không phải texblock

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.