由于我添加了一个启动画面,我的主窗体有时会(大约每20次一次)消失,就像它被最小化一样(它将是隐形但它仍然会在任务栏上,如果我点击它再次出现)。这是我的代码:
static class Program
{
private static SplashScreen splashScreen = null;
private static ManualResetEvent splashScreenWaiter = null;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ShowSplashAsync();
BuilderForm2 builderForm2 = new BuilderForm2();
builderForm2.Shown += new EventHandler(builderForm2_Shown);
Application.Run(builderForm2);
}
private static void HideSplash()
{
if (splashScreenWaiter != null)
{
splashScreenWaiter.WaitOne();
splashScreen.Invoke(new Action(splashScreen.Close));
splashScreenWaiter = null;
splashScreen = null;
}
}
private static void builderForm2_Shown(object sender, EventArgs e)
{
HideSplash();
}
private static void ShowSplashAsync()
{
splashScreenWaiter = new ManualResetEvent(false);
Thread splashThread = new Thread(ShowSplash);
splashThread.IsBackground = true;
splashThread.SetApartmentState(ApartmentState.STA);
splashThread.Start(splashScreenWaiter);
}
private static void ShowSplash(object resetEvent)
{
splashScreen = new SplashScreen((ManualResetEvent)resetEvent);
Application.Run(splashScreen);
}
}
这是SplashScreen代码:
public partial class SplashScreen : Form
{
private ManualResetEvent ResetEvent;
bool handleCreated = false;
bool formShown = false;
public SplashScreen(ManualResetEvent resetEvent)
{
ResetEvent = resetEvent;
HandleCreated += new EventHandler(SplashScreen_HandleCreated);
InitializeComponent();
}
private void SetResetEventIfReady()
{
if(handleCreated && formShown) ResetEvent.Set();
}
private void SplashScreen_Shown(object sender, EventArgs e)
{
formShown = true;
SetResetEventIfReady();
}
void SplashScreen_HandleCreated(object sender, EventArgs e)
{
handleCreated = true;
SetResetEventIfReady();
}
}
答案 0 :(得分:4)
没有跳出来。但是代码中存在非常严重的竞争条件。它与SystemEvents类有关。该类为控件提供重要通知,以便他们可以响应用户更改Windows主题。该类需要一个隐藏的通知窗口来接收有关用户所做更改的消息。
如果您的程序的第一个窗口是在工作线程而不是UI线程上创建的,则非常错误。这使得SystemEvents类在错误的线程(而不是你的工作线程btw)上创建该通知窗口。它引发的事件将从该线程调用。在错误的线程上获取事件会造成严重破坏,控件不是线程安全的。最典型的结果是,当您锁定工作站时,您将遇到奇怪的绘画问题或形式死锁。我可以想象你看到的错误也可以用这个来解释。
.NET框架已经为启动画面提供了优秀且经过时间考验的支持。我建议你使用它而不是自己旋转。检查this answer代码。
如果你想保留自己的,那么你可以通过在ShowSplashAsync调用之前将这行代码粘贴到Main方法来解决竞争问题:
Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { };