【问题标题】:Windows Form Application - Splash screen label not updatingWindows 窗体应用程序 - 启动屏幕标签未更新
【发布时间】:2015-06-11 02:11:37
【问题描述】:

我有一个 Windows 窗体应用程序,它应该显示一个带有标签字段的初始屏幕,我想在后台加载主窗体(称为welcome.cs)时更新该标签字段。初始屏幕显示和隐藏得很好,但标签没有更新。

我做了很多研究,但还没有找到解决方案。

程序.cs

/// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        using (new SingleGlobalInstance(1000))
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            SplashScreen splashscreen = new SplashScreen();
            splashscreen.ShowSplashScreen();

            Welcome welcome = new Welcome(splashscreen); //Takes some time to load
            splashscreen.CloseForm();
            Application.Run(welcome);

        }
    }

Splashscreen.cs

public partial class SplashScreen : Form
    {
        //Delegate for cross thread call to close
        private delegate void CloseDelegate();
        private delegate void UpdateStatusDelegate(string status);
        private static SplashScreen splashScreen;
        private Thread thread = null;

        public SplashScreen()
        {
            InitializeComponent();
        }

        public void ShowSplashScreen()
        {
            // Make sure it is only launched once.

            if (splashScreen != null)
                return;
            thread = new Thread(ShowForm);
            thread.IsBackground = true;
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
        }

        static private void ShowForm()
        {
            splashScreen = new SplashScreen();
            Application.Run(splashScreen);
        }

        public void CloseForm()
        {
            splashScreen.Invoke(new CloseDelegate(CloseFormInternal));
        }

        static private void CloseFormInternal()
        {
            splashScreen.Close();
        }

        public void UpdateStatus(string status)
        {
            splashScreen.Invoke(new UpdateStatusDelegate(UpdateStatusInternal), status);
        }

         private void UpdateStatusInternal (string status)
        {
             if (splashScreen != null && splashScreen.IsHandleCreated)
             {
                 lblStatus.Text = status;
             }

        }
    }

Welcome.cs

public Welcome(Splashscreen splashscreen)
{
        InitializeComponent();
        //Code to log the user into the system

        splashScreen.UpdateStatus("Logging in...");
        //my expectation is that UpdateStatus call will update the label displayed on the splash screen but it doesn't.

        //Do more stuff.....
}

它与多线程有关还是因为我在调用 UpdateStatus 之前在welcome.cs 中创建了一个新的启动画面实例?我该如何解决这个问题?

【问题讨论】:

  • 您正在Welcome 表单中创建一个 SplashScreen,而不是引用您已经显示的那个。您需要将现有初始屏幕的引用传递给Welcome 表单的构造函数,以便使用该现有引用。
  • 我错过了您尝试拥有多个 UI 线程的情况?那是非常错误的,删除创建自己的线程以运行的部分。您还不止一次拨打Application.Run,不建议这样做。
  • 它不起作用的原因是您在主例程中创建的引用也不是显示的实例,您创建了一个新的、私有的启动屏幕实例作为某种单例模式的错误尝试。按照您的编码方式,您无法获得对显示表单的实际引用。
  • 在阅读了您关于无法获得实际参考的评论后,我将 ShowSplashScreen、CloseForm、UpdateStatus 转换为静态方法。现在只有一个 SplashScreen 实例是在 ShowForm 中创建的。然后我在 SplashScreen 表单中添加了一个计时器,用于更新 lblStatus。有用!!但是,我会将其作为临时解决方案记录下来,并且肯定会对此主题进行更多研究以改进我的代码。

标签: c# winforms splash-screen


【解决方案1】:

您可以执行以下操作

 static void Main()
 {
     Application.EnableVisualStyles();
     Application.SetCompatibleTextRenderingDefault(false);

     string[] args = Environment.GetCommandLineArgs();

     // Creates the Splash
     splash = new FrmSplash();

     //Opens the Splash in a new Thread, this way any gifs, progress bars, lablels changes will work because the main thread isnt blocked
     var t = Task.Factory.StartNew(() =>
     {
         splash.ShowDialog();
     });

      while (!splash.Created) // wait the splash screen form load process
          System.Threading.Thread.Sleep(300);

     UpdateSplashMessage("Loading the program... Please wait");         
     // Some slow initialization code.
     // ...

     //Close splash screen
     CloseSplash();

     Application.Run(args);
 }

 static void CloseSplash()
 {
     splash.Invoke(new MethodInvoker(() =>
     {
         splash.Close(); // Closes the splash that is running in the other thread
     }));
 }

 static void UpdateSplashMessage(string msg)
 {
     splash.Invoke(new MethodInvoker(() =>
     {
         splash.AtualizarMensagem(msg);
     }));
 }

请注意,您需要在初始屏幕表单中创建一个名为 AtualizarMensagem(string str) 的方法,如下所示

public void AtualizarMensagem(string novaMsg)
{
    lblCarregando.Text = novaMsg;
}

我的“有用的snipets”文件夹中有这段代码,它总是对我有用。 希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 2018-08-23
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 1970-01-01
    • 2017-03-24
    相关资源
    最近更新 更多