调用时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是正确的,因为我在调试中看不到表单,所以在显示(或上次关闭)时出现了问题,但我不知道为什么。

调用时splashscreen为null

当在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的开销。如果你觉得十分之一秒太多了,你可以调整一下。

我知道现在已经很晚了,但希望这能帮助将来有同样问题的人。