我有一种情况,我希望主线程等待,而其他线程可以在主线程上调用,而无需调用Application.Run。
以下代码显示了我尝试实现的内容,但主线程和数据加载线程导致死锁。
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form1 = new Form1();
form1.Show();
Thread loadDataThread = new Thread(() =>
{
//Load Data that takes a long time
string title = LoadData();
form1.Invoke((Action)delegate { form1.Text = title; });
});
loadDataThread.Name = "Data Loading Thread";
loadDataThread.Start();
//wait for loading to be completed (deadlock)
loadDataThread.Join();
//Do more stuffs
Application.Run();
}
private static string LoadData()
{
Thread.Sleep(1000);
return "Hello Thread";
}
}
谢谢
答案 0 :(得分:1)
没有。您需要调用Application.Run
,然后在UI线程上安排委托。
P.S。最好使用Task
类而不是Control.Invoke
。
答案 1 :(得分:1)
调用只能起作用,因为在Windows窗体应用程序中,有一个消息循环在应用程序的整个生命周期内运行。如果在Thread.Join上被阻止,则消息循环不处理消息,这也意味着它不处理您的Invoke调用。
在.NET框架中有一些阻塞调用可以提取消息,但是你不能(也不应该)依赖这些,因为它们往往会产生重新入侵的错误。你的申请很难解决。
在等待数据加载时,不要阻止UI线程,而应该让它在后台运行,并显示启动画面。然后在最后,您可以使用BeginInvoke关闭启动屏幕并打开主屏幕或在加载结束时需要执行的任何操作。有点像...
static void Main() {
Application.EnableVisualStyles();
var splashScreen = new Form1();
var mainScreen = new Form2();
splashScreen.Show();
ThreadPool.QueueUserWorkItem(delegate {
LoadLotsOfData();
splashScreen.BeginInvoke(delegate {
splashScreen.Close();
mainScreen.Show();
});
}
Application.Run();
}