当前位置:   article > 正文

C#创建启动画面_c#启动画面连续静态图片

c#启动画面连续静态图片


文章来源:http://www.codeproject.com/Articles/3542/How-to-do-Application-Initialization-while-showing?rp=/KB/cs/AppLoadingArticle/AppLoading1.zip

AppLoading

Update 28.01.03

This article has been updated with Chris Austin's suggestion (Thanks Chris! And thanks to Phil Bolduc for the fix on Chris' stuff ;)) and an alternative (multithreaded) approach has been added, based on Jabes idea (Thanks Jabes!).

Introduction

This articles shows how to display a splash screen during your application initialization. This article assumes that you familiar with C# and the VS.NET IDE.

Background

I had put the lot of my initialization code into the main forms OnLoad() override. The code parsed configuration files, created control and the such. When my application started up, it looked like a mess: The main application form just didn't pop up nicely and ready to be used. I decided to create a Splash Screen, which should pop up right after starting the executable. While the splash screen was shown, I wanted to do my initialization and once that was done, I'd hide the splash screen and show the main application window. This article contains various approaches on how it can be realized.

Version A: Quick 'n Dirty

This version was the quick and dirty solution I came up with. Credits to Chris Austin for suggesting the usage of theApplicationContext class.

Preparations

  1. Create a new empty Windows Forms project.
  2. Add a new Form (for your splash screen and name it SplashForm).

1. Moving the Applications entry procedure

This is not required, but helps a beginning developer understand that the Main() entry point and the Form1 class into which it is put by default are not necessarily coupled. So let's create a new class called AppLoader and put the entry point in there. Once done, the class should look like this:

  1. public class AppLoader
  2. {
  3. public AppLoader()
  4. {
  5. }
  6. [STAThread]
  7. static void Main()
  8. {
  9. }
  10. }

Once completed, remove the code from your Form1.cs so that you don't end up having 2 entry points.

2. Creating the Splash Screen

Just create a new Windows Form, place a PictureBox on it and set a couple of properties just to make it look nicer. The form should be centered on the screen (StartPosition), be topmost (TopMost) and shouldn't have a border (FormBorderStyle). As for the PictureBox, set the Dock property to Fill and set the Image property to your splash image. That's it. In real life, you might want to write some code to display the application name, it's version, the registered user and a copyright notice, etc.

3. Modifying the MainForm's code

Now we need to do some modifications to the Form1 class. Since some initialization code can be put into the class constructor (such as reading files, etc.) some can't (like creating controls) since this is not available in the constructor. So you can't for example add controls to a forms Controls collection. Lets add a new public method (e.g. public void PreLoad(){...}). This function should look somewhat like this:

  1. public void PreLoad()
  2. {
  3. if (_Loaded)
  4. {
  5. // just return. this code can't execute twice!
  6. return;
  7. }
  8. // do your initialization here
  9. // ...
  10. // flag that we have loaded all we need.
  11. _Loaded = true;
  12. }

The _Loaded variable is a private bool, which should be initialized to false. You definitely should check this flag in your main forms OnLoad() override (which is called just before the form is shown the first time). For example:

  1. protected override void OnLoad(System.EventArgs e)
  2. {
  3. if (!_Loaded)
  4. {
  5. // good idea to throw an exception here.
  6. // the form shouldn't be shown w/o being initialized!
  7. return;
  8. }
  9. }

4. Modifying the AppLoader class

Here is the code for the AppLoader class. See the comments for information.

  1. public class AppLoader
  2. {
  3. private static ApplicationContext context;
  4. private static SplashForm sForm = new SplashForm();
  5. private static MainForm mForm = new MainForm();
  6. [STAThread]
  7. static void Main(string[] args)
  8. {
  9. // first we retrieve an application context for usage in the
  10. // OnAppIdle event handler
  11. context = new ApplicationContext();
  12. // then we subscribe to the OnAppIdle event...
  13. Application.Idle += new EventHandler(OnAppIdle);
  14. // ...and show our SplashForm
  15. sForm.Show();
  16. // instead of running a window, we use the context
  17. Application.Run(context);
  18. }
  19. private static void OnAppIdle(object sender, EventArgs e)
  20. {
  21. if(context.MainForm == null)
  22. {
  23. // first we remove the eventhandler
  24. Application.Idle -= new EventHandler(OnAppIdle);
  25. // here we preload our form
  26. mForm.PreLoad();
  27. // now we set the main form for the context...
  28. context.MainForm = mForm;
  29. // ...show it...
  30. context.MainForm.Show();
  31. // ...and hide the splashscreen. done!
  32. sForm.Close();
  33. sForm = null;
  34. }
  35. }
  36. }

Version B: Multithreaded

This version entirely based on Jabes idea. For more information read the Messages below. Thanks again to Jabes for letting me use his stuff in this article!

In this version, the SplashForm is shown in a separate thread and displays the current loading status (like in PhotoShop). You will want to multi-thread your splash screen if it is going to be on-screen for any length of time; by running the splash screen from its own message pump, screen redraws and other windows messages are processed correctly giving a more professional impression.

Preparations

  1. Create a new empty Windows Forms project.
  2. Add a new Form (for your splash screen and name it SplashForm).
  3. Repeat the steps from the previous Section which create the AppLoader class containing the entry point for the application. Leave the Method Body for Main() empty for now. Don't forget to remove the Main() method from the Form1 code!

1. Modify the SplashForm

In order to display the loading status on the form, we need to place a label on the form. For our example we call it lStatusInfo. Additionally we create a get/set Property named StatusInfo. After that we introduce a private string member called _StatusInfo which maps directly to the Property. The Property implementation should look like this:

  1. public string StatusInfo {
  2. set {
  3. _StatusInfo = value;
  4. ChangeStatusText();
  5. }
  6. get {
  7. return _StatusInfo;
  8. }
  9. }

ChangeStatusText() is a helper function which will be called each time the StatusInfo should be updated. It's implementation should look like this:

  1. public void ChangeStatusText() {
  2. try {
  3. if (this.InvokeRequired) {
  4. this.Invoke(new MethodInvoker(this.ChangeStatusText));
  5. return;
  6. }
  7. lStatusInfo.Text = _StatusInfo;
  8. }
  9. catch (Exception e) {
  10. // do something here...
  11. }
  12. }

The check for the InvokeRequired property is necessary because controls are not thread safe. So if you call a method on a control from a different thread (then the one which created the control) without marshalling the call into the proper thread, weird things might happen.

That's it. Let's create the Splasher class which maintains Thread creation, start and stop.

2. Creating the Splasher class

The static members Show()Close() and the Status property can be used as their names suggest to show and close the SplashWindow as well as to update the loading status displayed on the SplashForm (using the StatusInfoProperty previously created).

Here is what the implementation of the class looks like:

  1. public class Splasher
  2. {
  3. static SplashForm MySplashForm = null;
  4. static Thread MySplashThread = null;
  5. // internally used as a thread function - showing the form and
  6. // starting the messageloop for it
  7. static void ShowThread()
  8. {
  9. MySplashForm = new SplashForm();
  10. Application.Run(MySplashForm);
  11. }
  12. // public Method to show the SplashForm
  13. static public void Show()
  14. {
  15. if (MySplashThread != null)
  16. return;
  17. MySplashThread = new Thread(new ThreadStart(Splasher.ShowThread));
  18. MySplashThread.IsBackground = true;
  19. MySplashThread.ApartmentState = ApartmentState.STA;
  20. MySplashThread.Start();
  21. }
  22. // public Method to hide the SplashForm
  23. static public void Close()
  24. {
  25. if (MySplashThread == null) return;
  26. if (MySplashForm == null) return;
  27. try
  28. {
  29. MySplashForm.Invoke(new MethodInvoker(MySplashForm.Close));
  30. }
  31. catch (Exception)
  32. {
  33. }
  34. MySplashThread = null;
  35. MySplashForm = null;
  36. }
  37. // public Method to set or get the loading Status
  38. static public string Status
  39. {
  40. set
  41. {
  42. if (MySplashForm == null)
  43. {
  44. return;
  45. }
  46. MySplashForm.StatusInfo = value;
  47. }
  48. get
  49. {
  50. if (MySplashForm == null)
  51. {
  52. throw new InvalidOperationException("Splash Form not on screen");
  53. }
  54. return MySplashForm.StatusInfo;
  55. }
  56. }
  57. }

Ok, let’s look at what we have here:

The Show() method will create a new Thread using the static ShowThread function as a target. This function will simply show the Form and start a MessageLoop for it. The Close() method will again marshal a call to the SplashForms Close() method into the appropriate thread thus causing the form to close. The Status Property can be used to retrieve or update the StatusInfo displayed on the SplashScreen.

Here are some simple examples of their usage:

  1. ...
  2. // note that there is no instance required since those functions are static
  3. Splasher.Show(); // shows the SplashScreen
  4. // sets the status info displayed on the SplashScreen
  5. Splasher.Status = "Initializing Database Connection...";
  6. Splasher.Close(); // closes the SplashScreen
  7. ...

Modifying the AppLoader class

In order to use the Splasher class we have to modify our AppLoader class appropriately:

  1. public class AppLoader
  2. {
  3. public AppLoader()
  4. {
  5. }
  6. [STAThread]
  7. static void Main(string[] args)
  8. {
  9. Splasher.Show();
  10. DoStartup(args);
  11. Splasher.Close();
  12. }
  13. static void DoStartup(string[] args)
  14. {
  15. // do whatever you need to do
  16. Form1 f = new Form1();
  17. Application.Run(f);
  18. }
  19. }

First we show the SplashForm and set the initial StatusInfo text. Then we call DoStartup(), a good place to put any initialization code which doesn't require a form to be created.

Why moving the Startup Code into an extra function you might ask. The answer is simple: Since the Jitter works on a per function basis, it won’t need to do too much code before your Splash-Screen is actually getting shown on the screen.

To ensure that after you main Application form is loaded, it actually gets focused; you might want to put the following statement into the Form1 OnLoad override:

this.Activate();








声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/309510
推荐阅读
相关标签
  

闽ICP备14008679号