显示启动画面时,UI线程被阻止

时间:2012-08-04 10:28:10

标签: c# database winforms thread-safety

  

可能重复:
  C# Splash Screen Problem

我是c#的新手,我正在使用在软件启动时运行的启动画面..我在启动屏幕类中有一个函数来检查数据库。我正在使用线程来调用函数

        sc = new splashScreen();

        checkDLLThread = new Thread(new ThreadStart(sc.checkDLLS).BeginInvoke);
        checkDLLThread.Start();

        while (checkDLLThread.IsAlive)
        {
            Thread.Sleep(200);
        }

问题是在线程处于活动状态之前UI被阻止。最后它给我数据库连接状态消息。 这是我的代码。我使用过checkDLLThread.join()但它也不起作用。

4 个答案:

答案 0 :(得分:1)

启动画面只是在您的应用加载时“娱乐”用户的图片。使用app_load方法在启动时执行代码:

像这样:(在app.xaml和app.xaml.cs中)

    <Application /some references to stuff/ Startup="Application_Startup" >

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        // your startupcode
    }

此外,如果您不想打扰用户界面,我认为BackGroundworker类更适合这样的事情。

答案 1 :(得分:1)

取消阻止UI线程需要从事件处理程序返回。除此之外别无选择。这是一些伪代码:

OnStartup:
 Start new Thread
 Disable UI
 Show Splash Sceen
 Return!

Thread:
 Check Database
 if (not ok)
  Show Message box
  Exit Application
 else
  Enable UI
  Remove Splash Screen

诀窍是让线程显示消息,一旦完成就显示消息。不要等待线程,让线程自己做。

您的线程可能需要使用Invoke函数来访问UI。您可能不想阅读这一点,因为如果您想在后台线程上进行异步工作,则无法解决这个问题。

答案 2 :(得分:1)

以下代码在单独的线程上启动“启动画面”,同时您的应用程序(在我的示例中称为MainForm())加载或初始化。首先在你的“main()”方法中(在program.cs文件中,除非你已经重命名),你应该显示你的启动画面。这将是您希望在启动时向用户显示的WinForm或WPF表单。这是从main()启动,如下所示:

[STAThread]
static void Main()
{
    // Splash screen, which is terminated in MainForm.       
    SplashForm.ShowSplash();

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    // Run UserCost.
    Application.Run(new MainForm());
}

在您的SplashScreen代码中,您需要以下内容:

public partial class SplashForm : Form
{

    // Thredding.
    private static Thread _splashThread;
    private static SplashForm _splashForm;    

    public SplashForm()
    {
        InitializeComponent();
    }

    // Show the Splash Screen (Loading...)      
    public static void ShowSplash()    
    {        
        if (_splashThread == null)        
        {            
            // show the form in a new thread            
            _splashThread = new Thread(new ThreadStart(DoShowSplash));            
            _splashThread.IsBackground = true;            
            _splashThread.Start();        
        }    
    }    

    // Called by the thread    
    private static void DoShowSplash()    
    {        
        if (_splashForm == null)            
            _splashForm = new SplashForm();        
        // create a new message pump on this thread (started from ShowSplash)        
        Application.Run(_splashForm);
    }    

    // Close the splash (Loading...) screen    
    public static void CloseSplash()    
    {        
        // Need to call on the thread that launched this splash        
        if (_splashForm.InvokeRequired)            
            _splashForm.Invoke(new MethodInvoker(CloseSplash));        
        else            
            Application.ExitThread();    
    }

}

这将在单独的后台线程上启动splash表单,允许您同时继续呈现主应用程序。要显示有关加载的消息,您必须从主UI线程中提取信息,或者以纯粹美学的方式工作。要在初始化应用程序时关闭并关闭启动画面,请将以下内容放在默认构造函数中(如果需要,可以重载构造函数):

    public MainForm()
    {
        // ready to go, now initialise main and close the splashForm. 
        InitializeComponent();
        SplashForm.CloseSplash();
    }

上面的代码应该相对容易理解。

我希望这会有所帮助。

答案 3 :(得分:1)

你的方法很好,但你应该同时运行。好好利用static fields可以轻松完成工作。而不是:

    while (checkDLLThread.IsAlive)
    {
        Thread.Sleep(200);
    }

你应该:

  • 显示启动Form
  • 将表单设置为在开始时隐藏,即将Opacity设置为0
  • 在您的表单完全初始化后,在SplashForm 中稳定检查变量
  • 线程完成后,将Opacity设置回1。即变量变化

i.e.:

public Form1(){
     InitializeComponent();
     Opacity = 0;
     while(sc.IsComplete){}
     Opacity = 1;
}

SplashForm内,您应该类似

internal static bool IsComplete;

internal static void CheckDLLS()
{
    //after doing some stuff
    IsComplete = true;
}