gpt4 book ai didi

wpf - CurrentUICulture 忽略区域和语言设置

转载 作者:行者123 更新时间:2023-12-01 22:37:26 25 4
gpt4 key购买 nike

Windows 7 区域和语言对话框中的各种设置为 CurrentCulture 对象的属性提供值。然而,WPF控件似乎改用CurrentUICulture,导致完全无法尊重用户的偏好。

例如,在我的工作站上,WPF 控件似乎使用 en-US 的 CurrentUICulture,导致它们以美国格式 M/d/yyyy 显示日期,而不是在“区域和语言”对话框中指定的澳大利亚格式。

在数据绑定(bind)中显式指定 en-AU 区域性会导致相关控件使用默认的澳大利亚格式,但它继续忽略用户指定的格式。这很奇怪;进入应用程序我验证了 DateTimeFormatInfo.CurrentInfo == Thread.CurrentThread.CurrentCulture.DateTimeFormat (同一对象)和 DateTimeFormatInfo.CurrentInfo.ShortDatePattern == "yyyy-MM-dd"(我设置的值,以便我可以确定用户首选项是否或正在采用默认值)。一切都如预期,因此从表面上看,最大的问题是如何说服 WPF 控件和数据绑定(bind)使用 CurrentCulture 而不是 CurrentUICulture。

我们应该如何让 WPF 应用程序尊重区域和语言设置?

<小时/>

基于 Sphinxx 的答案,我重写了 Binding 类的两个构造函数,以提供与标准标记更完整的兼容性。

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

namespace ScriptedRoutePlayback
{
public class Bind : Binding
{
public Bind()
{
ConverterCulture = CultureInfo.CurrentCulture;
}
public Bind(string path) : base(path)
{
ConverterCulture = CultureInfo.CurrentCulture;
}
}
}
<小时/>

进一步的实验表明,您可以使用 x:Static 在标记中引用 System.Globalization.CultureInfo.CurrentCulture。这在运行时是完全成功的,但在设计时却是一场灾难,因为绑定(bind)编辑器不断删除它。更好的解决方案是使用辅助类来遍历窗口的 DOM 并修复它找到的每个 Binding 的 ConverterCulture。

using System;
using System.Windows;
using System.Windows.Data;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;

namespace ScriptedRoutePlayback
{
public static class DependencyHelper
{
static Attribute[] __attrsForDP = new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.SetValues | PropertyFilterOptions.UnsetValues | PropertyFilterOptions.Valid) };

public static IList<DependencyProperty> GetProperties(Object element, bool isAttached = false)
{
if (element == null) throw new ArgumentNullException("element");

List<DependencyProperty> properties = new List<DependencyProperty>();

foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(element, __attrsForDP))
{
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(pd);
if (dpd != null && dpd.IsAttached == isAttached)
{
properties.Add(dpd.DependencyProperty);
}
}

return properties;
}

public static IEnumerable<Binding> EnumerateBindings(DependencyObject dependencyObject)
{
if (dependencyObject == null) throw new ArgumentNullException("dependencyObject");

LocalValueEnumerator lve = dependencyObject.GetLocalValueEnumerator();

while (lve.MoveNext())
{
LocalValueEntry entry = lve.Current;

if (BindingOperations.IsDataBound(dependencyObject, entry.Property))
{
Binding binding = (entry.Value as BindingExpression).ParentBinding;
yield return binding;
}
}
}

/// <summary>
/// Use in the constructor of each Window, after initialisation.
/// Pass "this" as the dependency object and omit other parameters to have
/// all the bindings in the window updated to respect user customisations
/// of regional settings. If you want a specific culture then you can pass
/// values to recurse and cultureInfo. Setting recurse to false allows you
/// to update the bindings on a single dependency object.
/// </summary>
/// <param name="dependencyObject">Root dependency object for binding change treewalk</param>
/// <param name="recurse">A value of true causes processing of child dependency objects</param>
/// <param name="cultureInfo">Defaults to user customisations of regional settings</param>
public static void FixBindingCultures(DependencyObject dependencyObject, bool recurse = true, CultureInfo cultureInfo = null)
{
if (dependencyObject == null) throw new ArgumentNullException("dependencyObject");
try
{
foreach (object child in LogicalTreeHelper.GetChildren(dependencyObject))
{
if (child is DependencyObject)
{
//may have bound properties
DependencyObject childDependencyObject = child as DependencyObject;
var dProps = DependencyHelper.GetProperties(childDependencyObject);
foreach (DependencyProperty dependencyProperty in dProps)
RegenerateBinding(childDependencyObject, dependencyProperty, cultureInfo);
//may have children
if (recurse)
FixBindingCultures(childDependencyObject, recurse, cultureInfo);
}
}
}
catch (Exception ex)
{
Trace.TraceError(ex.Message);
}
}

public static void RegenerateBinding(DependencyObject dependencyObject, DependencyProperty dependencyProperty, CultureInfo cultureInfo = null)
{
Binding oldBinding = BindingOperations.GetBinding(dependencyObject, dependencyProperty);
if (oldBinding != null)
try
{
//Bindings cannot be changed after they are used.
//But they can be regenerated with changes.
Binding newBinding = new Binding()
{
Converter = oldBinding.Converter,
ConverterCulture = cultureInfo ?? CultureInfo.CurrentCulture,
ConverterParameter = oldBinding.ConverterParameter,
FallbackValue = oldBinding.FallbackValue,
IsAsync = oldBinding.IsAsync,
Mode = oldBinding.Mode,
NotifyOnSourceUpdated = oldBinding.NotifyOnSourceUpdated,
NotifyOnTargetUpdated = oldBinding.NotifyOnValidationError,
Path = oldBinding.Path,
StringFormat = oldBinding.StringFormat,
TargetNullValue = oldBinding.TargetNullValue,
UpdateSourceExceptionFilter = oldBinding.UpdateSourceExceptionFilter,
UpdateSourceTrigger = oldBinding.UpdateSourceTrigger,
ValidatesOnDataErrors = oldBinding.ValidatesOnDataErrors,
ValidatesOnExceptions = oldBinding.ValidatesOnExceptions,
XPath = oldBinding.XPath
};
//set only one of ElementName, RelativeSource, Source
if (oldBinding.ElementName != null)
newBinding.ElementName = oldBinding.ElementName;
else if (oldBinding.RelativeSource != null)
newBinding.Source = oldBinding.Source;
else
newBinding.RelativeSource = oldBinding.RelativeSource;
BindingOperations.ClearBinding(dependencyObject, dependencyProperty);
BindingOperations.SetBinding(dependencyObject, dependencyProperty, newBinding);
}
catch (Exception ex)
{
Trace.TraceError(ex.Message);
}
}

}
}

最佳答案

This SO post (WPF/Silverlight) 具有指向 this article 的链接(仅限 WPF),解释如何使用 CurrentCulture 作为应用程序的默认值。这能解决您的问题吗?

编辑:

使绑定(bind)使用“区域和语言”中的自定义设置而不是当前语言的默认设置需要更多技巧。 This post结论是,每个绑定(bind)的 ConverterCulture 也必须显式设置为 CultureInfo.CurrentCulture。以下是一些日期时间测试:

<!-- Culture-aware(?) bindings -->
<StackPanel DataContext="{Binding Source={x:Static sys:DateTime.Now}}" >

<!-- WPF's default en-US formatting (regardless of any culture/language settings) -->
<TextBlock Text="{Binding Path=.}" />

<!-- *Default* norwegian settings (dd.MM.YYY) -->
<TextBlock Text="{Binding Path=., ConverterCulture=nb-NO}" />

<!-- Norwegian settings from the "Region and Languague" dialog (d.M.YY) -->
<TextBlock Text="{Binding Path=., ConverterCulture={x:Static sysglb:CultureInfo.CurrentCulture}}" />

<!-- Hiding ConverterCulture initialization in our own custom Binding class as suggested here:
https://stackoverflow.com/questions/5831455/use-real-cultureinfo-currentculture-in-wpf-binding-not-cultureinfo-from-ietfl#5937477 -->
<TextBlock Text="{local:CultureAwareBinding Path=.}" />

</StackPanel>

自定义绑定(bind)类:

public class CultureAwareBinding : Binding
{
public CultureAwareBinding()
{
this.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
}
}

在挪威机器上,这一切最终看起来像这样:

WPF DateTime Bindings

关于wpf - CurrentUICulture 忽略区域和语言设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14149978/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com