我有一个带有数据网格和计时器的表单。 我创建了一个资源CalculationSheet并在DUTCH中进行翻译 - 英国(默认) - DUTCH
我用DUTCH语言启动应用程序。 当我选择新记录时,会弹出一个消息框。 它显示了正确的语言,荷兰语。 我也设置了计时器。
当计时器过去并再次显示消息框时,资源将以默认语言显示。
以下是该应用程序的主要入口点:
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
System.Threading.Thread.CurrentThread.CurrentUICulture =
new System.Globalization.CultureInfo("nl", true);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
这是回调代码:
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// shows in UK
MessageBox.Show(Properties.Resources.CalculationSheet);
}
private void Form1_Load(object sender, EventArgs e)
{
List<CalculationSheet> calculationSheets = new List<CalculationSheet>();
calculationSheets.Add(new CalculationSheet("a"));
calculationSheets.Add(new CalculationSheet("b"));
calculationSheets.Add(new CalculationSheet("c"));
this.dataGridView1.DataSource = calculationSheets;
this.m_Timer = new System.Timers.Timer();
this.m_Timer.Enabled = false;
this.m_Timer.Interval = 5000;
this.m_Timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
this.dataGridView1.SelectionChanged += new System.EventHandler(this.dataGridView1_SelectionChanged);
}
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
// shows in DUTCH
MessageBox.Show(Properties.Resources.CalculationSheet);
this.m_Timer.Enabled = true;
}
答案 0 :(得分:1)
System.Timers.Timer
class的回调在单独的线程上执行回调。
手动设置Application.CurrentCulture
property(或Thread.CurrentUICulture
property)时,它不会将CultureInfo
传递给其他创建的线程(CultureInfo
不会随{跨越线程的{3}}这就是你看到这个的原因;回调在另一个线程上执行,CultureInfo
未设置。
此测试用例显示CultureInfo.CurrentCulture
未流向其他线程(因此不在Timer
的回调中):
[TestMethod]
public void TestApplicationCurrentCultureInOtherThreads()
{
// Create the timer.
using (var t = new System.Timers.Timer(1000))
{
// The task completion source.
var tcs = new TaskCompletionSource<object>();
// Captured name.
CultureInfo capturedCulture = null;
// Set the current culture.
// The default for the system needs to be something other
// than "en-GB", mine is "en-US", which is why this
// test passes.
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");
// Copy t.
var tCopy = t;
// Event handler.
t.Elapsed += (s, e) => {
// Stop the timer.
tCopy.Stop();
// What's the captured name.
capturedCulture = CultureInfo.CurrentCulture;
// Complete the task.
tcs.SetResult(null);
};
// Start.
t.Start();
// Wait.
tcs.Task.Wait();
// Compare.
Assert.AreNotEqual(Thread.CurrentThread.CurrentUICulture,
capturedCulture);
}
}
你的回调在显示MessageBox.Show
方法时没有失败的原因是它不需要消息循环(它提供了它自己的一个)并且可以安全地从任何线程调用。
如果可能,我会将您需要的CultureInfo
存储在应用程序的一个位置,然后将其传递给其他线程上需要的任何方法(ExecutionContext
等方法)。 / p>
如果不可能,则必须在需要它的每个线程上设置Application.CurrentCulture
。但要小心,如果在定时器回调线程上执行此操作,这些线程来自线程池,因此您永远不会知道线程池线程上的当前文化是什么(因为它没有重置)。
那就是说,如果你在这些回调中做UI工作,那么你应该通过调用String.Format
将回调编组回UI线程(设置CultureInfo
的地方)。或Post
类上的Send
方法(您可以存储UI线程上调用的SynchronizationContext
中的值以从其他线程调用)。
您的Form1_Load
方法会存储SynchronizationContext
(在创建表单时设置):
private SynchronizationContext _synchronizationContext;
private void Form1_Load(object sender, EventArgs e)
{
// Capture the context.
_synchronizationContext = SynchronizationContext.Current;
// Rest of code.
...
}
然后您的timer_Elapsed
回调将如下所示:
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// Marshal back to the UI thread.
_synchronizationContext.Send(s => {
// Will now show in Dutch, as this call is taking place
// on the UI thread.
MessageBox.Show(Properties.Resources.CalculationSheet);
}, null);
}