.NET 启动画面组件






3.31/5 (21投票s)
一个允许动态创建和更新的启动画面。
引言
好吧,在互联网上搜索.NET的*免费*启动画面组件后,我感到非常不高兴。周围唯一像样的组件来自一家名为BitLaboratory的公司,以及Mr. Tom Clemont发布的另一篇CodeProject文章 (链接)。
我之前使用过BitLab的组件,但对其设计并不满意……而且他们不会发布源代码。:/
所以,我正在进行几个都需要启动页面的项目。而且,我不喜欢你那种基本的静态启动画面。我喜欢向用户展示后台正在发生的事情。所以,这是我的DGDev - 一个启动画面程序集。
背景
我想要实现的基本想法
- 多线程
- 自定义背景图片
- 自定义产品/程序信息空间
- 自定义更新状态空间
- 自定义启动画面窗体形状 (
TransparencyKey
)
Mr. Clemont的例子是一个很好的参考,但这完全是从头开始编写的。
示例
- 项目实现的屏幕录像:点击这里。
完整代码
实际代码非常短,而且非常容易理解。
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
属性。如果这样做,你会注意到TransparencyKey
在Form.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倾向于认为一切都是多余的,有时。 我已经更新了修复后的文件。