我有一个WPF应用程序,我想在整个应用程序中修改文化设置。这是一个简化的演示,说明了我想要实现的方式:
using System.Windows;
namespace CultureProblem3
{
public partial class MainWindow : Window
{
private System.Text.StringBuilder _sb;
public MainWindow()
{
InitializeComponent();
}
private void btn_Action_Click(object sender, RoutedEventArgs e)
{
var ci = new System.Globalization.CultureInfo(System.Globalization.CultureInfo.CurrentCulture.Name);
ci.NumberFormat.NumberGroupSeparator = "xxx";
System.Globalization.CultureInfo.DefaultThreadCurrentCulture = ci;
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = ci;
_sb = new System.Text.StringBuilder();
WriteInfo(_sb, "DefaultThreadCurrentCulture", System.Globalization.CultureInfo.DefaultThreadCurrentCulture);
WriteInfo(_sb, "DefaultThreadCurrentUICulture", System.Globalization.CultureInfo.DefaultThreadCurrentUICulture);
WriteInfo(_sb, "CultureInfo.CurrentCulture", System.Globalization.CultureInfo.CurrentCulture);
WriteInfo(_sb, "CultureInfo.CurrentUICulture", System.Globalization.CultureInfo.CurrentUICulture);
WriteInfo(_sb, "CurrentThread.CurrentCulture", System.Threading.Thread.CurrentThread.CurrentCulture);
WriteInfo(_sb, "CurrentThread.CurrentUICulture", System.Threading.Thread.CurrentThread.CurrentUICulture);
var t = new System.Threading.Thread(DoWork);
t.Start();
System.Threading.Thread.Sleep(1000);
MessageBox.Show(_sb.ToString());
}
private void DoWork()
{
WriteInfo(_sb, "CultureInfo.CurrentCulture - another thread", System.Globalization.CultureInfo.CurrentCulture);
WriteInfo(_sb, "CultureInfo.CurrentUICulture - another thread", System.Globalization.CultureInfo.CurrentUICulture);
WriteInfo(_sb, "CurrentThread.CurrentCulture - another thread", System.Threading.Thread.CurrentThread.CurrentCulture);
WriteInfo(_sb, "CurrentThread.CurrentUICulture - another thread", System.Threading.Thread.CurrentThread.CurrentUICulture);
}
private void WriteInfo(System.Text.StringBuilder sb, string desc, System.Globalization.CultureInfo ci)
{
sb.AppendLine($"{desc}: {ci.NumberFormat.NumberGroupSeparator}");
}
}
}
看起来它是可以工作的,但并不总是如此。当我在Windows 7上针对.NET 4.5.2运行应用程序或在Windows 10上使用.NET 4.5.2或.NET 4.6时,以下是输出结果(显示在消息框中):
DefaultThreadCurrentCulture: xxx
DefaultThreadCurrentUICulture: xxx
CultureInfo.CurrentCulture: xxx
CultureInfo.CurrentUICulture: xxx
CurrentThread.CurrentCulture: xxx
CurrentThread.CurrentUICulture: xxx
CultureInfo.CurrentCulture - another thread: xxx
CultureInfo.CurrentUICulture - another thread: xxx
CurrentThread.CurrentCulture - another thread: xxx
CurrentThread.CurrentUICulture - another thread: xxx
但是当我以.NET 4.6为目标,在Windows 10上运行应用程序时,会出现以下情况:
DefaultThreadCurrentCulture: xxx
DefaultThreadCurrentUICulture: xxx
CultureInfo.CurrentCulture: ,
CultureInfo.CurrentUICulture: ,
CurrentThread.CurrentCulture: ,
CurrentThread.CurrentUICulture: ,
CultureInfo.CurrentCulture - another thread: ,
CultureInfo.CurrentUICulture - another thread: ,
CurrentThread.CurrentCulture - another thread: ,
CurrentThread.CurrentUICulture - another thread: ,
有人能解释一下它们之间的区别吗?我已经查看了.NET 4.6兼容性列表,但我没有找到任何可能影响它的东西(或者我视力不好)。我认为最相关的变化是CultureInfo.CurrentCulture和CultureInfo.CurrentUICulture属性现在是可读写的,而不是只读的(来源)。
我知道我只设置了DefaultThreadCurrentCulture/DefaultThreadCurrentUICulture,而没有明确设置CurrentCulture/CurrentUICulture。但是根据MSDN的说法,我认为在我的情况下没问题(如果我错了,请纠正我)。
如果您没有显式设置应用程序域中正在执行的任何现有线程的区域性,则设置DefaultThreadCurrentCulture属性也会更改这些线程的区域性。但是,如果这些线程在另一个应用程序域中执行,则它们的区域性由该应用程序域中的DefaultThreadCurrentCulture属性定义,或者如果未定义默认值,则由默认系统区域性定义。因此,我们建议您始终明确设置主应用程序线程的区域性,并且不依赖于DefaultThreadCurrentCulture属性来定义主应用程序线程的区域性。
此外,这并不能解释不同操作系统之间行为的差异,是吗?
有趣的是,如果我替换
var ci = new System.Globalization.CultureInfo(System.Globalization.CultureInfo.CurrentCulture.Name);
ci.NumberFormat.NumberGroupSeparator = "xxx";
System.Globalization.CultureInfo.DefaultThreadCurrentCulture = ci;
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = ci;
带有
var ci = new System.Globalization.CultureInfo(System.Globalization.CultureInfo.CurrentCulture.Name);
ci.NumberFormat.NumberGroupSeparator = "xxx";
System.Globalization.CultureInfo.DefaultThreadCurrentCulture = ci;
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = ci;
var ci2 = new System.Globalization.CultureInfo(System.Globalization.CultureInfo.CurrentCulture.Name);
ci2.NumberFormat.NumberGroupSeparator = "yyy";
System.Threading.Thread.CurrentThread.CurrentCulture = ci2;
System.Threading.Thread.CurrentThread.CurrentUICulture = ci2;
输出如下:
在 Windows 7 上使用 .NET 4.5.2 或在 Windows 10 上使用 .NET 4.5.2:
DefaultThreadCurrentCulture: xxx
DefaultThreadCurrentUICulture: xxx
CultureInfo.CurrentCulture: yyy
CultureInfo.CurrentUICulture: yyy
CurrentThread.CurrentCulture: yyy
CurrentThread.CurrentUICulture: yyy
CultureInfo.CurrentCulture - another thread: xxx
CultureInfo.CurrentUICulture - another thread: xxx
CurrentThread.CurrentCulture - another thread: xxx
CurrentThread.CurrentUICulture - another thread: xxx
在Windows 7上的.NET 4.6或Windows 10上的.NET 4.6:
DefaultThreadCurrentCulture: xxx
DefaultThreadCurrentUICulture: xxx
CultureInfo.CurrentCulture: yyy
CultureInfo.CurrentUICulture: yyy
CurrentThread.CurrentCulture: yyy
CurrentThread.CurrentUICulture: yyy
CultureInfo.CurrentCulture - another thread: yyy
CultureInfo.CurrentUICulture - another thread: yyy
CurrentThread.CurrentCulture - another thread: yyy
CurrentThread.CurrentUICulture - another thread: yyy
.NET 4.5.2的行为符合我的预期,我认为.NET 4.6的行为是错误的。有趣的是,几天前我可以发誓它“正常”工作(尽管我不能100%确认)。我只是猜测,但是一些Windows更新可能会改变其行为?