调用时splashscreen为null
本文关键字:null splashscreen 调用 | 更新日期: 2023-09-27 17:58:17
我有一个防溅屏:
public partial class LoadingScreen : Form
{
private delegate void CloseDelegate();
private static LoadingScreen loadingscreen;
private LoadingScreen()
{
InitializeComponent();
}
private static void ShowForm()
{
loadingscreen = new LoadingScreen();
Application.Run(loadingscreen);
}
public static void ShowLoadingscreen()
{
if (loadingscreen != null)
return;
System.Threading.Thread thread = new System.Threading.Thread(LoadingScreen.ShowForm);
thread.IsBackground = true;
thread.SetApartmentState(System.Threading.ApartmentState.STA);
thread.Start();
}
public static void CloseForm()
{
loadingscreen.Invoke(new CloseDelegate(LoadingScreen.CloseFormInternal));
}
private static void CloseFormInternal()
{
loadingscreen.Close();
loadingscreen = null;
}
}
当数据网格忙于刷新时(它需要一些绘图,而我们庞大的数据需要一段时间),当用户使用文本框搜索它触发的东西时,也会调用它,因为我们需要重新绘制所有内容。触发防溅屏的代码:
private void EditGrid()
{
LoadingScreen.ShowLoadingscreen();
CheckItems();
EditGridVisibility();
LoadingScreen.CloseForm();
}
当用户在搜索框中键入3、4或5个字符时,我会在LoadingScreen.CloseForm();
上得到一个NullReferenceException我得到一个NullRef是正确的,因为我在调试中看不到表单,所以在显示(或上次关闭)时出现了问题,但我不知道为什么。
当在ShowLoadingScreen有时间启动线程并创建loadingScreen之前调用CloseForm时,会发生此错误。
在后台线程上加载/处理数据并在主UI线程上显示对话框几乎总是更容易。但如果无法做到这一点,请确保对话框在关闭或中止创建之前显示。
一个粗略的解决方案是使线程全局化。。。
public static void CloseForm()
{
if (loadingscreen == null)
{
_thread.Abort();
return;
}
loadingscreen.Invoke(new CloseDelegate(CloseFormInternal));
}
我使用过John的解决方案,它在大多数情况下都很好。但是,在某些情况下,_thread.Abort()
调用会导致应用程序崩溃,没有任何异常。查找它,使用Thread.Abort()
似乎是一种非常糟糕的做法,就像杀死线程一样(请参阅此、此、此和许多其他在线内容),所以正如其他人所说,不要使用线程。中止()
这里有一个完美的解决方案:
public static void CloseForm()
{
// Loop for a maximum of 100ms if the screen hasn't yet been loaded.
for (var i = 0; i < 100; i++)
{
if (loadingScreenForm != null && loadingScreenForm.IsHandleCreated)
{
break;
}
Thread.Sleep(1);
}
// Don't try to close if it is already closed.
// If the screen form is still null after waiting, it was most likely already closed.
if (loadingScreenForm != null && loadingScreenForm.IsHandleCreated)
{
loadingScreenForm.Invoke(new CloseDelegate(CloseFormInternal));
}
}
我的代码的细节要求我检查句柄是否已经创建,但你可能可以不用它。在这种情况下,这将给代码增加100ms的开销。如果你觉得十分之一秒太多了,你可以调整一下。
我知道现在已经很晚了,但希望这能帮助将来有同样问题的人。