65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET 启动画面组件

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.31/5 (21投票s)

2008年10月13日

CC (ASA 2.5)

3分钟阅读

viewsIcon

115446

downloadIcon

6088

一个允许动态创建和更新的启动画面。

引言

好吧,在互联网上搜索.NET的*免费*启动画面组件后,我感到非常不高兴。周围唯一像样的组件来自一家名为BitLaboratory的公司,以及Mr. Tom Clemont发布的另一篇CodeProject文章 (链接)。

我之前使用过BitLab的组件,但对其设计并不满意……而且他们不会发布源代码。:/

所以,我正在进行几个都需要启动页面的项目。而且,我不喜欢你那种基本的静态启动画面。我喜欢向用户展示后台正在发生的事情。所以,这是我的DGDev - 一个启动画面程序集。

背景

我想要实现的基本想法

  • 多线程
  • 自定义背景图片
  • 自定义产品/程序信息空间
  • 自定义更新状态空间
  • 自定义启动画面窗体形状 (TransparencyKey)

Mr. Clemont的例子是一个很好的参考,但这完全是从头开始编写的。

示例

screenshot.jpg

完整代码

实际代码非常短,而且非常容易理解。

using System;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

namespace DGDev
{
    public class SplashScreen : Form
    {
        private const double OpacityDecrement = .08;
        private const double OpacityIncrement = .05;
        private const int TimerInterval = 50;
        private static Boolean FadeMode;
        private static Boolean FadeInOut;
        private static Image BGImage;
        private static String Information;
        private static String Status;
        private static SplashScreen SplashScreenForm;
        private static Thread SplashScreenThread;
        private static Color TransparentKey;
        private Label ProgramInfoLabel;
        private Label StatusLabel;
        private System.Windows.Forms.Timer SplashTimer;
        private IContainer components;
        private delegate void UpdateLabel();
        private delegate void CloseSplash();

        #region Public Properties & Methods

        /// <summary>
        /// These methods can all be called to set configurable 
                  /// parameters for the Splash Screen
        /// </summary>
        public String SetInfo
        {
            get { return Information; }
            set
            {
                Information = value;
                if(ProgramInfoLabel.InvokeRequired)
                {
                    var InfoUpdate = 
                        new UpdateLabel(UpdateInfo);
                    Invoke(InfoUpdate);
                }
                else
                {
                    UpdateInfo();
                }
            }
        }

        public String SetStatus
        {
            get { return Status; }
            set
            {
                Status = value;
                if(StatusLabel.InvokeRequired)
                {
                    var StatusUpdate = 
                        new UpdateLabel(UpdateStatus);
                    Invoke(StatusUpdate);
                }
                else
                {
                    UpdateStatus();
                }
            }
        }

        public Image SetBackgroundImage
        {
            get { return BGImage; }
            set
            {
                BGImage = value;
                if (value != null)
                {
                    BackgroundImage = BGImage;
                    ClientSize = BackgroundImage.Size;
                }
            }
        }

        public Color SetTransparentKey
        {
            get { return TransparentKey; }
            set
            {
                TransparentKey = value;
                if (value != Color.Empty)
                    TransparencyKey = SetTransparentKey;
            }
        }

        public Boolean SetFade
        {
            get { return FadeInOut; }
            set
            {
                FadeInOut = value;
                Opacity = value ? .00 : 1.00;
            }
        }

        public static SplashScreen Current
        {
            get
            {
                if (SplashScreenForm == null)
                    SplashScreenForm = new SplashScreen();
                return SplashScreenForm;
            }
        }

        public void SetStatusLabel(Point StatusLabelLocation, 
                Int32 StatusLabelWidth, Int32 StatusLabelHeight)
        {
            if (StatusLabelLocation != Point.Empty)
                StatusLabel.Location = StatusLabelLocation;
            if (StatusLabelWidth == 0 && StatusLabelHeight == 0)
                StatusLabel.AutoSize = true;
            else
            {
                if (StatusLabelWidth > 0)
                    StatusLabel.Width = StatusLabelWidth;
                if (StatusLabelHeight > 0)
                    StatusLabel.Height = StatusLabelHeight;
            }
        }

        public void SetInfoLabel(Point InfoLabelLocation, 
                Int32 InfoLabelWidth, Int32 InfoLabelHeight)
        {
            if (InfoLabelLocation != Point.Empty)
                ProgramInfoLabel.Location = InfoLabelLocation;
            if (InfoLabelWidth == 0 && InfoLabelHeight == 0)
                ProgramInfoLabel.AutoSize = true;
            else
            {
                if (InfoLabelWidth > 0)
                    ProgramInfoLabel.Width = InfoLabelWidth;
                if (InfoLabelHeight > 0)
                    ProgramInfoLabel.Height = InfoLabelHeight;
            }
        }

        public void ShowSplashScreen()
        {
            SplashScreenThread = new Thread(ShowForm) 
                {IsBackground = true, Name = "SplashScreenThread"};
            SplashScreenThread.Start();
        }

        public void CloseSplashScreen()
        {
            if (SplashScreenForm != null)
            {
                if(InvokeRequired)
                {
                    var ClosingDelegate = 
                        new CloseSplash(HideSplash);
                    Invoke(ClosingDelegate);
                }
                else
                {
                    HideSplash();
                }
            }
        }
        #endregion

        public SplashScreen()
        {
            InitializeComponent();
        }

        private static void ShowForm()
        {
            Application.Run(SplashScreenForm);
        }

        private void UpdateStatus()
        {
            StatusLabel.Text = SetStatus;
        }

        private void UpdateInfo()
        {
            ProgramInfoLabel.Text = SetInfo;
        }

        private void SplashTimer_Tick(object sender, EventArgs e)
        {
            if(FadeMode) // Form is opening (Increment)
            {
                if (Opacity < 1.00)
                    Opacity += OpacityIncrement;
                else
                    SplashTimer.Stop();
            }
            else // Form is closing (Decrement)
            {
                if(Opacity > .00)
                    Opacity -= OpacityDecrement;
                else
                    Dispose();
            }
            
        }

        #region InitComponents

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.ProgramInfoLabel = new System.Windows.Forms.Label();
            this.StatusLabel = new System.Windows.Forms.Label();
            this.SplashTimer = new System.Windows.Forms.Timer
                            (this.components);
            this.SuspendLayout();
            // 
            // ProgramInfoLabel
            // 
            this.ProgramInfoLabel.BackColor = 
                    System.Drawing.Color.Transparent;
            this.ProgramInfoLabel.Location = 
                    new System.Drawing.Point(56, 52);
            this.ProgramInfoLabel.Name = "ProgramInfoLabel";
            this.ProgramInfoLabel.Size = 
                    new System.Drawing.Size(100, 23);
            this.ProgramInfoLabel.TabIndex = 0;
            // 
            // StatusLabel
            // 
            this.StatusLabel.BackColor = 
                    System.Drawing.Color.Transparent;
            this.StatusLabel.Location = 
                    new System.Drawing.Point(59, 135);
            this.StatusLabel.Name = "StatusLabel";
            this.StatusLabel.Size = new System.Drawing.Size(100, 23);
            this.StatusLabel.TabIndex = 1;
            // 
            // SplashScreen
            // 
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.Controls.Add(this.StatusLabel);
            this.Controls.Add(this.ProgramInfoLabel);
            this.FormBorderStyle = 
                System.Windows.Forms.FormBorderStyle.None;
            this.Name = "SplashScreen";
            this.ShowInTaskbar = false;
            this.StartPosition = 
                System.Windows.Forms.FormStartPosition.CenterScreen;
            this.ResumeLayout(false);

        }

        #endregion

        private void SplashScreen_Load(object sender, EventArgs e)
        {
            if (SetFade)
            {
                FadeMode = true;
                SplashTimer.Interval = TimerInterval;
                SplashTimer.Start();
            }
        }

        private void HideSplash()
        {
            if(SetFade)
            {
                FadeMode = false;
                SplashTimer.Start();
            }
            else
                Dispose();
        }
    }
}

使用 DLL

让我们快速浏览一下我正在进行的另一个程序,现在它适合使用启动画面了。

Program.cs

using System;
using System.Drawing;
using System.Windows.Forms;
using DGDev;

namespace Raum
{
    static class Program
    {
        private static SplashScreen splash;

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

            const String resourceName = "Splash.png";
            var InfoLabel = new Point(25, 92);
            var StatusLabel = new Point(28, 261);

            splash = SplashScreen.Current;
            splash.SetTransparentKey = Color.Fuchsia;
            var rs = GetResourceStream(resourceName);
            splash.SetBackgroundImage = new Bitmap(rs);
            splash.SetInfoLabel(InfoLabel, 499, 117);
            splash.SetStatusLabel(StatusLabel, 490, 17);
            splash.ShowSplashScreen();
            splash.SetInfo = "This program is just an example.";

            AppDomain currentDomain = AppDomain.CurrentDomain;
            currentDomain.AssemblyLoad += asmLoadHandler;

            Application.Run(new RaumMain());
        }

        private static System.IO.Stream GetResourceStream(String resource)
        {
            var ea = System.Reflection.Assembly.GetExecutingAssembly();
            foreach (String curResource in ea.GetManifestResourceNames())
            {
                if (curResource.EndsWith(resource))
                {
                    return ea.GetManifestResourceStream
                                (curResource);
                }
            }
            return null;
        }

        static void asmLoadHandler(object sender, AssemblyLoadEventArgs args)
        {
            splash.SetStatus = "Loading Assembly: " + 
                args.LoadedAssembly.GetName().Name + " ...";
        }
    }
}

更仔细的观察

那么,那里发生了什么?!通过使用这个*SplashScreen.dll*,你可以在一分钟内完成你的启动画面,并有几个选项可以使用。

// This will be our BackgroundImage of the Splash
const String resourceName = "Splash.png";  
// This creates a Location point for our ProgramInfo label.
var InfoLabel = new Point(25, 92);  
// This creates a Location point for our Status label.
var StatusLabel = new Point(28, 261);  

// You must call this before attempting to assign any properties! 
// It creates/initializes all the form controls. 
splash = SplashScreen.Current; 

// Say you want a custom shape Splash Screen. 
// You can use this to set the TransparencyKey. 
splash.SetTransparentKey = Color.Fuchsia; 

// Call our function to pull the image from our Resources.resx
var rs = GetResourceStream(resourceName); 
// Set the Splash BackgroundImage
splash.SetBackgroundImage = new Bitmap(rs); 

//This method uses 3 parameters. (Point Location, Int32 Width, Int32 Height)
//If you set both Width & Height to 0, than the label will set AutoSize = true. 
//Default is false.

splash.SetInfoLabel(InfoLabel, 499, 117);

splash.SetStatusLabel(StatusLabel, 490, 17); // Same as above, but for the Status Label

splash.ShowSplashScreen();  // You must call this to RUN the Splash Screen 
splash.SetInfo = "This program is just an example.";

动态加载更新

我更喜欢向用户展示正在加载哪些.NET程序集。在这里,我们看到每当一个程序集被加载时,它就会更新启动画面上的状态标签。

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyLoad += asmLoadHandler;

static void asmLoadHandler(object sender, AssemblyLoadEventArgs args)
{
    splash.SetStatus = "Loading Assembly: " + 
            args.LoadedAssembly.GetName().Name + " ...";
}

关闭启动画面

关于这个类的一个很棒的特性是,它可以在你的代码中的任何地方被访问。所以,在你的Main窗体加载后,只需使用以下代码关闭启动画面

splash = SplashScreen.Current;
splash.CloseSplashScreen();

关注点

已知问题

  • 当使用自定义形状窗体/TransparencyKey时,你不能使用SetFade属性。如果这样做,你会注意到TransparencyKeyForm.Opacity达到*1.00*之前不起作用。

问题/问题/建议

我还没有实现try/catch块,所以目前没有处理异常。将会进行更多的测试,并添加新功能以及适当的异常处理。

如果你有问题,请随时给我发邮件,或在下面的讨论论坛中发帖。

如果你将其用于专有的商业软件,请帮助一个破产的大学生,并捐赠一美元。

历史

  • 2008年10月13日 - v1.0.0.0发布。
  • 2008年10月24日 下午 2:05 - 修复了演示下载链接。 对不起,伙计们。
  • 2008年10月23日 下午 4:42 - 上传了新文件。 有一些错误需要修复。 代码现在应该适用于所有.NET Framework版本。 此外,SetFade已修复。
  • 2008年10月13日 晚上 10:08 - 对不起,伙计们,在使用JetBrains自动重构代码后,它在设计器代码中删除了一些必要的程序集构造函数。 Reshaper倾向于认为一切都是多余的,有时。 我已经更新了修复后的文件。
© . All rights reserved.