2011-04-29 10 views
30

W moim przypadku:Use "prawdziwy" CultureInfo.CurrentCulture w WPF Binding, nie CultureInfo z IetfLanguageTag

Mam TextBlock Binding do właściwości typu DateTime. Chcę, aby był wyświetlany zgodnie z ustawieniami regionalnymi użytkownika.

<TextBlock Text="{Binding Date, StringFormat={}{0:d}}" /> 

ja ustawienie właściwości języka jako WPF XAML Bindings and CurrentCulture Display mówi:

this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag); 

Ale z tej linii kodu to po prostu wyświetla tekst jako formatu domyślnego CultureInfo z IetfLanguageTag z CurrentCulture mówi, a nie jako efektywna wartość wybrana w ustawieniach regionu systemowego mówi:

(np. dla "DE-DE" dd.MM.rrrr jest używany zamiast wybierz ed yyyy-MM-dd)

Region settings: not the default but yyy-MM-dd is used

Czy istnieje sposób wiązania wykorzystuje poprawny format bez definiowania ConverterCulture na każdy wiążąca?

W kodzie

string.Format("{0:d}",Date); 

wykorzystuje odpowiednie ustawienia kultury.

edit:

inny sposób, który nie działa zgodnie z oczekiwaniami (jak this.Language = ... robi):

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

i

<Binding Source="{x:Static glob:CultureInfo.CurrentCulture}" 
Path="IetfLanguageTag" 
ConverterCulture="{x:Static glob:CultureInfo.InvariantCulture}" /> 
+1

Sprawdź następujące elementy: http://stackoverflow.com/questions/2764615/wpf-stringformat-0c-showing-as-dollars –

+2

@Pavlo: odpowiedź na to pytanie wykorzystuje również IetfLanguageTag do uzyskania informacji CultureInfo. –

Odpowiedz

22

Można utworzyć podklasę wiązania (np. CultureAwareBinding), która automatycznie ustawia konwerter do aktualnej kultury po utworzeniu.

To nie jest idealne rozwiązanie, ale prawdopodobnie jest to jedyne, ponieważ z mocą wsteczną zmuszanie Binding do poszanowania kultury może złamać inny kod w WPF, który zależy od tego zachowania.

Daj mi znać, jeśli potrzebujesz więcej pomocy!

+0

dziękuję za odpowiedź. to rozwiązanie zachowuje się jak jedyne możliwe. –

+0

"ponieważ z mocą wsteczną zmuszanie Binding do poszanowania kultury może złamać inny kod w WPF, który zależy od tego zachowania." - Twierdzę, że w dłuższej perspektywie gorsze jest utrzymywanie takiego zachowania, niż wprowadzenie krótkoterminowej przerwy. Mogą też to naprawić, ale korzystają z funkcji wiązania zespołu .NET, aby wykryć, kiedy aplikacja oczekuje starszej wersji i zachowuje dla nich złamane zachowanie. To szaleństwo, że ten błąd jest w WPF od 12 lat i nie ma wbudowanego własnego "CultureAwareBinding". – Dai

2

Twoja druga próba była blisko i doprowadziła mnie do rozwiązania, które działa dla mnie.

Problem z ustawieniem konwertera jest taki, że używany jest tylko w przypadku konwertera. Więc po prostu stworzyć prosty StringFormatConverter które ma format jako parametru:

public sealed class StringFormatConverter : IValueConverter 
{ 
    private static readonly StringFormatConverter instance = new StringFormatConverter(); 
    public static StringFormatConverter Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 

    private StringFormatConverter() 
    { 
    } 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     return string.Format(culture, (string)parameter, value); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotSupportedException(); 
    } 
} 

Następnie można wyregulować wiązania swojej (zakładając zaimportowaniu nazw przetwornicy jako „my”)

<TextBlock Text="{Binding Date, Converter={x:Static my:StringFormatConverter.Instance}, ConverterCulture={x:Static glob:CultureInfo.CurrentCulture}, ConverterParameter={}{0:d}}" /> 
-1

Jak o zmiana lanaguge w kodzie?

+0

Ta metoda ignoruje ustawienia niestandardowe w oknie dialogowym "Region i język" i po prostu używa nazwy do uzyskania języka. –

+0

Jest to najprostsze rozwiązanie i działa dobrze dla mnie też (Windows Phone 7). @Markus k: Przepraszam, nie złapałem tego, co próbujesz powiedzieć/wyjaśnić? – hfrmobile

+1

@ hfmobile Co miał na myśli to, że jeśli wybierzesz język w ustawieniach regionalnych (np. W Niemczech niemieckich), a następnie ręcznie zmienisz dowolne ustawienie (poza krótką datą zmiany na dMrrrr), ustawienie sugerowanego języka nie spowoduje nowy format. – Goran

15

Jest to rozszerzenie odpowiedzi od aKzenT. Zaproponowali, że powinniśmy stworzyć podklasę klasy Binding i ustawić ConverterCulture na CurrentCulture. Mimo że odpowiedź jest bardzo prosta, wydaje mi się, że niektórzy ludzie mogą nie być zbyt wygodni w jej implementacji, dlatego dzielę się wersją kodu odpowiedzi aKzenT z przykładem, jak z niej korzystać w XAML.

using System; 
using System.Globalization; 
using System.Windows.Data; 

namespace MyWpfLibrary 
{ 
    public class CultureAwareBinding : Binding 
    { 
     public CultureAwareBinding() 
     { 
      ConverterCulture = CultureInfo.CurrentCulture; 
     } 
    } 
} 

Przykład jak to wykorzystać w XAML

1) Musisz zaimportować przestrzeń nazw w pliku XAML:

<Page 
    ... 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:myWpfLib="clr-namespace:MyWpfLibrary;assembly=<assembly_name>" 
    ... 
> 

2) Wykorzystanie w realnym świecie na CultureAwareBinding

<Textblock Text="{myWpfLib:CultureAwareBinding Path=Salary, Source=Contact, StringFormat={}{0:C}}" /> 
+0

Podoba mi się szczegółowe wyjaśnienie na ten temat. Wszelkie dane wejściowe dotyczące błędów korygujących dla określonych powiązań? Rezultatem jest coś takiego: "Typ" CultureAwareBinding "nie zawiera konstruktora, który ma określoną liczbę argumentów." – Poken1151

+0

Nie widziałem jeszcze tego błędu. Musiałbym zobaczyć kod, aby określić, dlaczego tak się stanie. Być może mógłbyś zamieścić nowe pytanie na Stack Overflow i dodać tutaj link do niego? –

+1

Dzięki, poprawiłem błąd. To było złe kodowanie, widocznie {Binding ITEM-NAME ....} nie jest dobre, potrzebowałem {Binding Path = ITEM-NAME, ...}. To rozwiązało mój błąd (który nadal byłby kompilowany w obu przypadkach). – Poken1151

-1

Problem polegający na unikaniu używania "this.Language = XmlLanguage.GetLanguage (Thread.Current Thread.CurrentCulture.Name); " nie jest tak powszechny. Nie znam tutaj żadnego użytkownika, który zmieniłby format daty na amerykański lub japoński, ponieważ przynajmniej żaden użytkownik nie wie, że taka zmiana jest możliwa (i nie wiem jak to zrobić) ... oczywiście "language =" nie jest idealny, ale przez wiele lat praktyki WPF i Silverlight nigdy nie widziałem problemu tego rodzaju z jakimkolwiek użytkownikiem ... Nadal używam sztuczki "Langage =", jest to proste i pokrywają 100% rzeczywistych potrzeb. Oczywiście inne rozwiązania wydają się lepsze, ale nie ma potrzeby (i widziałem kilka implementacji, które są dalekie od doskonałych w porównaniu do rozwiązania "language =").

+1

@ Olivier: Po prostu mówię "inni użytkownicy nawet nie wiedzą o takiej opcji", "z mojej wielu, wielu lat wiedzy o WPF i Silverlight, którą znam najlepiej" lub nawet twierdzę, że ktokolwiek wie, że "prawdziwe potrzeby" są aroganckie. Nic nie wiesz o preferencjach prawie 99% ludzi tej planety - tak jak wszyscy inni deweloperzy tego nie robią. Zaakceptuj, że jest potrzeba i udziel pomocy. Używanie YYYY-MM-DD jest formatem daty, który chciałbym, aby cały świat raczej się zgodził niż używał regionalnych. IMHO, "od dużego do małego" jest bardziej przydatne, zwłaszcza gdy chodzi o sortowanie, niż jakikolwiek inny format. – Yoda

1

Używam tego kodu z odpowiednimi wynikami do moich potrzeb. Mam nadzieję, że może to wypełnić :-)! Być może lepiej rzucić wyjątek, jeśli nie można "TryParse". Zależy od Ciebie.

public sealed class CurrentCultureDoubleConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     return ((double)value).ToString((string)parameter ?? "0.######", CultureInfo.CurrentCulture); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     double result; 
     if (Double.TryParse(value as string, NumberStyles.Number, CultureInfo.CurrentCulture, out result)) 
     { 
      return result; 
     } 

     throw new FormatException("Unable to convert value:" + value); 
     // return value; 
    } 
} 

Zastosowanie:

<Window 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:simulatorUi="clr-namespace:SimulatorUi" 
     xmlns:Converter="clr-namespace:HQ.Wpf.Util.Converter;assembly=WpfUtil" x:Class="SimulatorUi.DlgTest" 
     Title="DlgTest" Height="300" Width="300"> 
    <Window.DataContext> 
     <simulatorUi:DlgTestModel/> 
    </Window.DataContext> 

    <Window.Resources> 
     <Converter:CurrentCultureDoubleConverter x:Key="CurrentCultureDoubleConverter"/> 
    </Window.Resources> 

    <Grid> 
     <TextBox Text="{Binding DoubleVal, Converter={StaticResource CurrentCultureDoubleConverter}}"/> 
    </Grid> 
</Window> 
2

wymyśliłem hack/obejście że unika aktualizacji wszystkich powiązań. Dodaj ten kod do konstruktora twojego głównego okna.

XmlLanguage language = XmlLanguage.GetLanguage("My-Language"); 
typeof(XmlLanguage).GetField("_compatibleCulture", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(language, CultureInfo.CurrentCulture); 
this.Language = language; 

Ponieważ jest to przy użyciu odbicia nie ma gwarancji, że będzie działać w przyszłości, ale na razie to robi (.NET 4.6).

3

Przed wprowadzeniem dowolnego interfejsu użytkownika wpisz następujący wiersz kodu. To działało dla mnie.

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

(i usunąć wszystkie parametry wyraźne kultura)