Problemas de localización StringFormat en wpf
datetime localization (10)
Como ya se dijo, XAML se establece de forma predeterminada en la cultura invariante (en-US), y puede usar
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
para establecer la cultura en la cultura predeterminada para el idioma de la cultura actual. Pero el comentario es incorrecto; esto no utiliza la cultura actual, ya que no verá ninguna personalización que el usuario haya realizado, siempre será la predeterminada para el idioma.
Para utilizar realmente la cultura actual con personalizaciones, tendrá que configurar el ConverterCulture
junto con StringFormat
, como en
Text="{Binding Day, StringFormat=''d'', ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}}"
con gl
definido como un espacio de nombres global en su elemento raíz
xmlns:gl="clr-namespace:System.Globalization;assembly=mscorlib"
En WPF 3.5SP1 utilizo la última característica StringFormat en DataBindings:
<TextBlock Text="{Binding Path=Model.SelectedNoteBook.OriginalDate, StringFormat=''f''}"
FontSize="20"
TextTrimming="CharacterEllipsis" />
El problema al que me enfrento es que la fecha siempre está formateada en inglés ... ¿aunque mi sistema está en francés? ¿Cómo puedo forzar la fecha para seguir la fecha del sistema?
Defina el siguiente espacio de nombres xml:
xmlns:gl="clr-namespace:System.Globalization;assembly=mscorlib"
Ahora mira esta fantástica solución:
<TextBlock Text="{Binding Path=Model.SelectedNoteBook.OriginalDate, StringFormat=''f'', ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}" FontSize="20"TextTrimming="CharacterEllipsis" />
Soy consciente de que esta no es una solución global y la necesitarás en cada uno de tus enlaces, pero seguramente eso solo es bueno XAML. Por lo que sé, la próxima vez que las actualizaciones de enlace utilizará el CultureInfo.CurrentCulture
correcto o lo que haya proporcionado.
Esta solución actualizará inmediatamente tus enlaces con los valores correctos, pero parece que hay un montón de código para algo tan raro e inocuo.
El código completo para cambiar la localización también en elementos como <Run />
es esto:
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
Si desea cambiar la información cultural en tiempo de ejecución, podría usar un comportamiento (ver a continuación)
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();
}
}
Si está trabajando en código en lugar de XAML, puede configurar ConverterCulture de la siguiente manera:
binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Felicitaciones a @KZeise por señalar la sutil diferencia entre usar la definición de cultura predeterminada y usar la definición de cultura personalizada del usuario.
Si necesita cambiar el idioma mientras el programa se está ejecutando, puede cambiar la propiedad Idioma en su elemento raíz (no estoy seguro si esto tiene un efecto instantáneo o si el elemento secundario debe ser recreado, en mi caso esto funciona al menos)
element.Language = System.Windows.Markup.XmlLanguage.GetLanguage(culture.IetfLanguageTag);
Simplemente inserte el atajo cultural en la etiqueta de nivel superior:
xml:lang="de-DE"
p.ej:
<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>
Solo quería agregar que la respuesta de Loraderon funciona muy bien en la mayoría de los casos. Cuando coloco la siguiente línea de código en mi App.xaml.cs, las fechas en mis TextBlocks están formateadas en la cultura correcta.
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
Digo ''la mayoría de los casos''. Por ejemplo, esto funcionará de la caja:
<TextBlock Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}}" />
--> "16 mei 2013" (this is in Dutch)
... pero cuando se usa Run en un TextBlock, DateTime se formatea en la cultura predeterminada.
<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")
Para que esto funcione, necesitaba la respuesta de Gusdor , es decir, agregar ConverterCulture = {x: Static gl: CultureInfo.CurrentCulture} al Enlace.
<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)
Espero que esta respuesta adicional sea útil para alguien.
Use Label (incluyendo Cultture) y no texblock
// 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)));