我有一个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}");
}
}
}
它似乎有用,但并非总是如此。当我以.NET 4.5.2为目标并在Windows 7上运行app,在Windows 10上运行.NET 4.5.2或在Windows 7上运行.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上运行app时,我得到了以下内容:
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: ,
有人可以解释一下我的区别吗?我已经检查了this .NET 4.6 compatibility list,但我找不到任何可能影响它的东西(或者我是盲目的)。我假设最近的相关变化是CultureInfo.CurrentCulture和CultureInfo.CurrentUICulture属性现在是读写而不是只读(source)。
我知道我只设置了DefaultThreadCurrentCulture / DefaultThreadCurrentUICulture而没有显式设置CurrentCulture / CurrentUICulture。但是according to 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 Update无法改变这种行为吗?
答案 0 :(得分:6)
从.NET 4.6开始,来自正在运行的线程的CurrentCulture将流向它创建的新线程,并在执行排队项时流向ThreadPool线程。您可以在MSDN上阅读有关缓解此更改的更多信息:Mitigation: Culture and Asynchronous Operations
以下是上述文档中列出的用于切换回旧行为的选项:
将所需的CultureInfo.CurrentCulture或CultureInfo.CurrentUICulture属性显式设置为异步任务中的第一个操作
启动时致电AppContext.SetSwitch("Switch.System.Globalization.NoAsyncCurrentCulture", true);
。
覆盖.config
<configuration>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Globalization.NoAsyncCurrentCulture=true" />
</runtime>
</configuration>