T.J*_*aer 53 .net wpf localization
我有一个.NET 4.0 WPF应用程序,用户可以在其中更改语言(文化)我只是让用户选择一种语言,创建一个相应的CultureInfo并设置:
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
在C#代码中,这很好用.然而,在WPF控制中,文化仍然是美国的.这意味着例如日期将以美国格式显示,而不是对当前文化正确的日期.
显然,这不是一个错误.根据MSDN和StackOverflow上的一些博客文章和文章,WPF语言不会自动遵循当前的文化.在您执行此操作之前,它是en-US:
FrameworkElement.LanguageProperty.OverrideMetadata(
    typeof(FrameworkElement),
    new FrameworkPropertyMetadata(
        XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag)));
请参阅wpf中的StringFormat Localization问题.
我不完全理解这里发生了什么.似乎所有frameworkelements上的Language属性都设置为当前文化.无论如何,它的工作原理.我在应用程序启动时执行此操作,现在所有控件都按预期工作,例如日期根据当前文化格式化.
但现在的问题是:根据MSDN FrameworkElement.LanguageProperty.OverrideMetadata只能调用一次.事实上,如果我再次调用它(当用户更改语言时),它将抛出异常.所以我还没有真正解决我的问题.
问题:如何在我的应用程序生命周期中不止一次地和可靠地更新WPF中的文化?
(我在研究时发现了这个:http://www.nbdtech.com/Blog/archive/2009/03/18/getting-a-wpf-application-to-pick-up-the-correct-regional.aspx and it似乎他有一些工作在那里.但是,我无法想象如何在我的应用程序中执行此操作.似乎我必须在所有打开的窗口和控件中更新语言并刷新所有现有绑定等.)
我要来这里.
我成功地使用OverrideMetadata()OP提到的方法做到了这一点:
var lang = System.Windows.Markup.XmlLanguage.GetLanguage(MyCultureInfo.IetfLanguageTag);
FrameworkElement.LanguageProperty.OverrideMetadata(
  typeof(FrameworkElement), 
  new FrameworkPropertyMetadata(lang)
);
但是,我仍然在我的WPF中找到了实例,其中系统文化正在应用于日期和数字值.原来这些是<Run>元素中的值.之所以发生这种情况是因为System.Windows.Documents.Run该类没有继承System.Windows.FrameworkElement,因此元数据的覆盖FrameworkElement显然没有效果.
System.Windows.Documents.Run从而继承其Language财产System.Windows.FrameworkContentElement.
因此,显而易见的解决方案是以FrameworkContentElement相同的方式覆盖元数据.可惜的是,这样做时抛出异常(PropertyMetadata已注册类型System.Windows.FrameworkContentElement),所以我不得不做它的未来子孙的祖先Run,而不是,System.Windows.Documents.TextElement:
FrameworkContentElement.LanguageProperty.OverrideMetadata(
  typeof(System.Windows.Documents.TextElement), 
  new FrameworkPropertyMetadata(lang)
);
这解决了我所有的问题.
还有一些子类FrameworkContentElement(在此列出),为了完整性,它们的元数据也应该被覆盖.
我不知道如何绕过"无法多次调用OverrideMetadata"异常.
作为解决方法,当用户更改应用程序中的UI文化时,您可以使用该文化重新启动应用程序,将新文化作为命令行参数传递.除非您的用户经常改变文化,否则这听起来像是一个合理的解决方案.
我从来没有找到办法完全按照我在问题中提出的要求.在我的情况下,我最终通过让我的所有usercontrol继承自包含以下内容的超类来解决它:
/// <summary>
///   Contains shared logic for all XAML-based Views in the application. 
///   Views that extend this type will have localization built-in.
/// </summary>
public abstract class ViewUserControl : UserControl
{
    /// <summary>
    ///   Initializes a new instance of the ViewUserControl class.
    /// </summary>
    protected ViewUserControl()
    {
        // This is very important! We make sure that all views that inherit 
        // from this type will have localization built-in. 
        // Notice that the following line must run before InitializeComponent() on 
        // the view. Since the supertype's constructor is executed before the type's 
        // own constructor (which call InitializeComponent()) this is as it 
        // should be for classes extending this
        this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);
    }
}
当用户更改语言时,我会创建当前正在运行的任何用户控件的新实例.
这解决了我的问题.但是,我仍然想要一种"自动"执行此操作的方法(即无需跟踪任何实例化对象).
只是我的两分钱:在尝试使用我的德语程序集实现 ComponentOne WPF 控件(DataGrid 和 C1DatePicker)时几乎发疯后,我偶然发现了这个页面。
这似乎是以正确的方式指导的:我刚刚将上述代码输入到我的 App.xaml.cs / Application_startup 例程中,现在 C1DatePicker 的德语日期/时间格式终于起作用了。
在那之后必须立即测试 DataGrid。
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        FrameworkElement.LanguageProperty.OverrideMetadata(
            typeof(FrameworkElement),
            new FrameworkPropertyMetadata(
            System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag)));
    }
谢谢!
更新:为 WPF 测试了 C1DataGrid - 有效!这解决了我在应用程序中使用国际日期/时间设置时遇到的所有问题。伟大的!