在winform应用程序开发中,我们通常习惯于将系统的初始化代码(例如:读取配置文件、实例化持久数据层、设置主窗体界面)写在主窗体的构造函数或其OnLoad事件中,如果这些系统初始化代码的运行需要较长一段时间的话,就需要设置一个启动屏幕随时显示系统当前正在执行的操作以增强用户体验;另外,某些情况下你的系统可能需要用户输入密码方可正常使用,那么如何处理登陆窗口和系统主窗体的关系呢?本文将这两个知识点以实例的方式做了一下演示,希望对初学者能有所帮助。
准备工作
1、打开vs2005,创建一个名为“SplashScreen”的windows应用程序项目(C#)
2、删除自动生成的 Form1.cs并添加一个名为frmMain.cs的windows窗体
3、修改应用程序的主入口static void Main()函数中Application.Run(new Form1());为Application.Run(new frmMain());
一、编写启动屏幕的核心代码
首先创建一个名为ISplashForm的接口,该接口包含一个名为SetStatusInfo的方法以用来在启动屏幕上设置系统加载状态,代码如下:
{
void SetStatusInfo(string NewStatusInfo);
}
接着创建一个名为Splasher的类,该类包含Show、 Close 两个静态方法以显示、关闭启动屏幕,另外还有一个名为Status的只读属性,最终代码如下:
{
private static Form m_SplashForm = null;
private static ISplashForm m_SplashInterface = null;
private static Thread m_SplashThread = null;
private static string m_TempStatus = string.Empty;
/// <summary>
/// 显示启动画面
/// </summary>
public static void Show(Type splashFormType)
{
if (m_SplashThread != null)
return;
if (splashFormType == null)
{
throw (new Exception("必须设置启动窗体"));
}
m_SplashThread = new Thread(
new ThreadStart(delegate()
{
CreateInstance(splashFormType);
Application.Run(m_SplashForm);
}
));
m_SplashThread.IsBackground = true;
m_SplashThread.SetApartmentState(ApartmentState.STA);
m_SplashThread.Start();
}
/// <summary>
/// 设置加载信息
/// </summary>
public static string Status
{
set
{
if (m_SplashInterface == null || m_SplashForm == null)
{
m_TempStatus = value;
return;
}
m_SplashForm.Invoke(
new SplashStatusChangedHandle(delegate(string str) { m_SplashInterface.SetStatusInfo(str); }),
new object[] { value }
);
}
}
/// <summary>
/// 关闭启动画面
/// </summary>
public static void Close()
{
if (m_SplashThread == null || m_SplashForm == null) return;
try
{
m_SplashForm.Invoke(new MethodInvoker(m_SplashForm.Close));
}
catch (Exception)
{
}
m_SplashThread = null;
m_SplashForm = null;
}
private static void CreateInstance(Type FormType)
{
object obj = FormType.InvokeMember(null,
BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null);
m_SplashForm = obj as Form;
m_SplashInterface = obj as ISplashForm;
if (m_SplashForm == null)
{
throw (new Exception("启动窗体类型必须是System.Windows.Forms.Form的子类"));
}
if (m_SplashInterface == null)
{
throw (new Exception("启动窗体必须实现ISplashForm接口"));
}
if (!string.IsNullOrEmpty(m_TempStatus))
m_SplashInterface.SetStatusInfo(m_TempStatus);
}
private delegate void SplashStatusChangedHandle(string NewStatusInfo);
}
二、创建启动屏幕
在项目中添加一个名为frmSplash.cs的windows窗体,设置该窗体的StartPosition属性为CenterScreen,TopMost属性为true,FormBorderStyle属性为None;为窗体选择一个合适的背景图片(临时先随便找个差不多大小的就可以)并设置窗体的大小与图片大小一致。拖动一个Label到frmSplash窗体上一个合适位置,并更名为lbStatusInfo,切换到代码视图实现ISplashForm接口,关键代码如下:
{
public frmSplash()
{
InitializeComponent();
}
#region ISplashForm 成员
void ISplashForm.SetStatusInfo(string NewStatusInfo)
{
lbStatusInfo.Text = NewStatusInfo;
}
#endregion
}
三、启动屏幕演示的最后工作
调整主窗体frmMain.cs的WindowState属性为Maximized,并修改其构造函数如下:
{
Splasher.Status = "正在创建主窗体";
System.Threading.Thread.Sleep(1000);
InitializeComponent();
Splasher.Status = "正在读取配置文件";
System.Threading.Thread.Sleep(1500);
Splasher.Status = "正在安装系统插件";
System.Threading.Thread.Sleep(1500);
Splasher.Status = "再休眠1秒钟";
System.Threading.Thread.Sleep(1000);
Splasher.Close();
}
修改应用程序的主入口static void Main()函数如下:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Splasher.Show(typeof(frmSplash));
Application.Run(new frmMain());
}
做完以上工作,编译项目并运行即可看到启动屏幕的显示效果。
四、创建登陆窗口
在项目中添加一个名为frmLogin.cs的windows窗体,设置该窗体的StartPosition属性为CenterScreen,FormBorderStyle属性为FixedSingle,MaximizeBox属性为false。向窗体添加一个GroupBox、两个Label、两个TextBox和两个Button,分别设置两个Label的Text属性为“用户:”和“密码:”,设置两个TextBox的Name为“txtUser”和“txtPass”,设置两个Button的Name属性为“btnLogin”和“btnExit”,对应Text设置为“登陆”和“退出”,设置btnExit的DialogResult属性为Cancel,然后双击btnLogin切换到代码视图编写如下代码:
private void btnLogin_Click(object sender, EventArgs e)
{
string temp = CheckInput();
if (!string.IsNullOrEmpty(temp))
{
MessageBox.Show(temp, "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
txtUser.Focus();
return;
}
this.DialogResult = DialogResult.OK;
}
private string CheckInput()
{
string strUser=txtUser.Text.Trim();
string strPass=txtPass.Text.Trim();
if (string.IsNullOrEmpty(strUser))
return "登陆用户不得为空! ";
if (string.IsNullOrEmpty(strPass))
return "登陆密码不得为空! ";
if (strUser != "test" || strPass != "test")
return "登陆用户或登陆密码错误! ";
return string.Empty;
}
五、调整应用程序的主入口函数
修改应用程序的主入口static void Main()函数如下:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
frmLogin frm = new frmLogin();
if (DialogResult.OK == frm.ShowDialog())
{
Splasher.Show(typeof(frmSplash));
frmMain MyMainForm = new frmMain();
Application.Run(MyMainForm);
}
else
{
Application.Exit();
}
}
编译后运行便可看到整体效果了,注意,这里的登陆验证只是判断用户名和密码是否均为test。
另外,为了在应用程序加载完毕后将主窗体展示给用户,可在frmMain_Load中添加如下代码:
this.Show();
this.Activate();