目录
“对知识的投资总是能带来最大的利益。”
本杰明·富兰克林
介绍
在本文中,我想讨论Splash\Login Forms创建的问题。我经常在论坛上偶然发现新手程序员关于Splash\Login Forms的问题。在我看来,这些问题的答案往往没有提供全面的信息。所以我决定写这篇文章。它充分描述了这些问题和解决方案。
首先,我想讨论一个问题——是什么导致了这些问题的出现?在我看来,当我们开始在Windows系统中执行程序时,它与有关Windows体系结构和Windows进程的信息不足或概念模糊有关。这是主要问题。因此,让我们解决它。我不打算复述一本关于Windows的大好书,没有意义。我只想让您有机会了解在Windows中创建实例程序。这将使您了解如何创建Splash\Login Forms。
什么是流程?
首先,我们将讨论“Windows中的进程”的定义。进程——它是可执行程序的副本,它由两个组件组成:
- 内核的一个对象,操作系统通过该对象管理进程。它保留有关该过程的static信息。
- 包含进程的可执行代码和数据的地址空间。
该过程本身不做任何事情,即它是惰性的。为了让它做某事,它应该至少有一个线程。线程负责在进程的地址空间中执行代码。因此,当进程启动时,操作系统会自动创建主线程,而主线程又可以生成其他线程。此外,如果我们希望我们的应用程序响应鼠标移动、按钮单击等,我们必须在线程中创建一个消息循环。所以我们有一些结构:进程——线程——消息循环。如果我们想关闭程序,我们需要关闭主消息循环。当您关闭主窗体或执行Application.Exit()方法以及主线程中的ExitThread()方法时,就会发生这种情况。
我该怎么做?
上面讨论的所有内容都是当我们选择使用Windows窗体应用程序创建项目模板时,Visual Studio会自动创建。有了这些知识,请看一下代码,我们肯定都反复看到过:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
当你调用一个方法Application.Run (new Form1 ())Form时,我们创建一个新线程,它创建一个消息循环,以及一个类的对象并显示它。让我们仔细考虑这种方法。此方法已重载,并且可能具有以下选项:
- Run()
- Run(ApplicationContext)
- Run(Form)
(有关其他信息,请参阅此链接。
在本文的上下文中,我们对第一种重载方法不感兴趣,当然,除非您决定在不安全的代码中创建一些东西,即我们已经讨论过的第三种方法。但第二个是我们将特别感兴趣的。这将创建对象类ApplicationContext,该类负责创建线程和消息的标准周期。现在一切都很简单——我们必须创建一个ApplicationContext类的后代类LoginTestContext,我们将使用应用程序形式创建一个逻辑:
public class LoginTestContext: ApplicationContext
{
// here we can declare the all forms application and manage it directly
//(show, close, set as MainForm and so on)
private frmLogIn fLogin;
private frmMain fMain;
public LoginTestContext()
{
CreateSplashForm();
CreateLoginForm();
}
}
(有关其他信息,请参阅此链接。)
我们进入应用程序的入口点将如下所示:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Run the application with our context. It is splash, log and main forms
Application.Run(new LoginTestContext());
}
创建启动窗体
就是这样!Splash窗体会在我们需要的时候显示。在这里,您可以做一些真正必要的操作,例如加载任何资源,同时显示进度条或其他类型的信息,而不是休眠线程。
private static void CreateSplashForm()
{
Form fSplash = new Form();
fSplash.BackgroundImage = System.Drawing.Image.FromFile(@"backg.bmp");
fSplash.BackgroundImageLayout = ImageLayout.Center;
fSplash.FormBorderStyle = FormBorderStyle.None;
fSplash.StartPosition = FormStartPosition.CenterScreen;
fSplash.TopMost = true;
//it sets transparency for the background of image
fSplash.TransparencyKey = System.Drawing.Color.White;
//set the splash form size and we are sure the image fit to the form
fSplash.Width = (int)fSplash.BackgroundImage.PhysicalDimension.Width;
fSplash.Height = (int)fSplash.BackgroundImage.PhysicalDimension.Height;
fSplash.Show();
System.Threading.Thread.Sleep(2000);
fSplash.Close();
}
创建登录表单
现在我们将讨论登录表单的建立问题。“登录”窗体位于“启动窗体”之后。在任何情况下,登录表单都应关闭。当它自行关闭时,我们必须确定是否在应用程序中进行登录:
private void CreateLoginForm()
{
fLogin = new frmLogIn();
fLogin.Closed += new EventHandler(fLogin_Closed);
fLogin.TopMost = true;
fLogin.Show();
}
void fLogin_Closed( object sender, EventArgs e )
{
if (LWork.LoginWork.Login)
{
fMain = new frmMain();
this.MainForm = fMain; //set the main message loop application in this form
fMain.Show();
}
else
{
ExitThread();
}
}
注册过程是在static类LoginWork中实现的。
public static void DoLogin( string NikName, string Password )
{
if (IsExistNikName(NikName))
{
if (_user.Password == HashString(Password))
{
_Logged = true;
}
}
else
_Logged = false;
}
查找列表IsExistNikName (string name)中的用户名的功能使用lambda表达式UserData => UserData.Nikname == NikName实现。在这个例子中,实体lambda表达式的解释过于简单。有关lambda表达式的更多信息,请参阅此链接。
private static bool IsExistNikName( string NikName )
{
if (_UserDataList.Count == 0)
{
return false;
}
//here I use a lambda expression for the searching the nikname
//in the user data list
_user = _UserDataList.FirstOrDefault(UserData => UserData.Nikname == NikName);
if (String.IsNullOrEmpty(_user.Nikname))
{
return false;
}
return true;
}
为了安全起见,使用以下函数对用户的密码进行哈希处理:
public static string HashString( string s )
{
//encode string to the array of bytes
byte[] data = Encoding.Default.GetBytes(s);
//hashing
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(data);
//do hexadecimal-formatted string
StringBuilder sb = new StringBuilder();
foreach (byte item in result)
{
sb.Append(item.ToString("X"));
}
return sb.ToString();
}
保存、加载注册用户数据的过程是使用XML序列化和UserData结构实现的。数据存储在本地XML文件中:
[Serializable]
public struct UserData
{
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
private string _Nikname;
public string Nikname
{
get { return _Nikname; }
set { _Nikname = value; }
}
private string _Password;
public string Password
{
get { return _Password; }
set { _Password = value; }
}
}
结论
这就是我想告诉你的关于这个话题的全部内容。我希望我成功地充分揭示了本文的主题。
https://www.codeproject.com/Articles/106751/Splash-and-Login-Forms-Problems-and-Solutions