splashscreen在调用时变为null

时间:2014-04-15 08:50:12

标签: c# winforms splash-screen

我有一个闪屏:

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,因为我没有看到调试中的形式,所以在显示(或关闭最后一次)时出现了问题,但我不明白为什么。

2 个答案:

答案 0 :(得分:2)

在ShowLoadingScreen有时间旋转它的线程并创建loadingScreen之前调用CloseForm时会发生此错误。

在后台线程上加载/处理数据并在主UI线程上显示对话框几乎总是更容易。但如果无法做到这一点,请确保在取消对话框或中止其创建之前显示对话框。

一个粗略的解决方案是使线程全局化......

public static void CloseForm()
{
    if (loadingscreen == null)
    {
        _thread.Abort();
        return;
    }
    loadingscreen.Invoke(new CloseDelegate(CloseFormInternal));
}

答案 1 :(得分:0)

我使用过John的解决方案,并且在大多数情况下都能正常工作。但是,在某些情况下,_thread.Abort()调用会导致应用程序崩溃,没有任何例外。查找起来,使用Thread.Abort()似乎是非常糟糕的做法,就像杀死一个帖子一样(请参阅thisthisthisthis和许多其他在线),正如其他人所说,不要使用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的开销。如果你觉得十分之一秒太多,你可以调整它。

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