总算忙过一段时间了,两个月前看了一点点关于 C# 的实战视频,现在看回来居然忘得七七八八,果然学习还是要写笔记,好记性不如烂笔头。。
1 项目框架
用户界面模块数据访问模块DAL(即如同 Service 层、Dao 层 与 Mapper 层,其中还包含如SQLHelper
类)数据库映射实体类模块Models(即 Bean 层)其它辅助类(如数字验证)程序的配置文件本项目基于两层架构进行设计,用户界面模块为表现层,数据访问模块为数据访问层,而实体类模块并不能算一个独立的数据层,它只能算是程序中的一个模块。
注意:
1、在
解决方案
下右键选择新增类库
,类库之间的引用,右键打开对应的模块引用
点击添加引用
,选择对应的类库名即可。2、在模块中添加的
类
默认的访问修饰符是internal
,所以要在外部模块中引用就需要显式地声明该类访问修饰符为public
。3、在添加完
类库
之后,要右键解决方案
点击生成解决方案
或者 右键对应的模块点击重新生成
,这样对应的类库才能编译到对应的dll
文件中。
1.1 数据访问模块
由于数据访问模块需要与数据库进行链接访问,所以其下新增的类需要添加以下命名空间:
// 数据库使用 sqlServerusing System.Data;using System.Data.SqlClient;
// 数据库使用 mysqlusing System.Data;using MySql.Data.MySqlClient;
1.1.1SQLHelper
类
在 数据访问模块(DAL) 中,基本都是Service
类,而像SQLHelper
这种工具类为了区分开来,最好就是在 数据访问模块(DAL)下新增一个文件夹,并将其声明在此。
注意:如果直接新增如名为
SQLHelper
的文件夹,并在其直接添加SQLHelper
类,此时SQLHelper
的命名空间即为DAL.SQLHelper
,这样即使是在 DAL 模块下的其他Service
类也需要显式引用该命名空间才能使用SQLHelper
类,所以最简洁的方法是先直接在 DAL 模块下声明SQLHelper
类,声明完之后直接拖动到SQLHelper
文件夹中,此时该命名空间也依旧是DAL
。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Data;using MySql.Data.MySqlClient;using System.Configuration;// 引入读取配置文件类所在的命名空间,要在根目录下建立配置文件,比如此项目的根目录是在 StudentManager 表现层当中namespace DAL{public class SQLHelper{public static string connString = ConfigurationManager.ConnectionStrings["connString"].ToString();/// <summary>/// 增,删,改/// </summary>/// <param name="sql"></param>public static int executeNonQuery(string sql){MySqlConnection conn = new MySqlConnection(connString);MySqlCommand cmd = new MySqlCommand(sql, conn);try{conn.Open();int result = cmd.ExecuteNonQuery();return result;}catch (Exception ex){// 写入日志throw ex;}finally{conn.Close();}}/// <summary>/// 获取单一数据/// </summary>/// <param name="sql"></param>/// <returns></returns>public static object GetSingleResult(string sql){MySqlConnection conn = new MySqlConnection(connString);MySqlCommand cmd = new MySqlCommand(sql, conn);try{conn.Open();object result = cmd.ExecuteScalar();return result;}catch (Exception ex){// 写入日志throw ex;}finally{conn.Close();}}/// <summary>/// 获取 结果集 的查询/// </summary>/// <param name="sql"></param>/// <returns></returns>public static MySqlDataReader getReader(string sql){MySqlConnection conn = new MySqlConnection(connString);MySqlCommand cmd = new MySqlCommand(sql, conn);try{conn.Open();MySqlDataReader result = cmd.ExecuteReader(CommandBehavior.CloseConnection); // 关闭数据库链接,不能在 finally 语句中关闭链接,因为如果关闭了,MySqlDataReader 而又尚未读取,关闭之后 MySqlDataReader 也就读取不到了return result;}catch (Exception ex){// todo 写入日志throw ex;conn.Close();}}}}
值得注意的是,链接数据库的字符串需要声明在配置文件中,这样修改链接字符串就无需重新编译程序,因此就要学习 C# 如何使用配置文件了。
1.1.2 配置文件App.config
参考文章:《C# 配置文件App.config的使用操作》
在 表现层模块中即 winform 模块右键新建配置文件App.config
(因为表现层所在的目录是将来应用程序启动时的根目录),然后添加相关的子节点,如添加数据库链接相关信息,节点名称可以为connectionStrings
,eg:
<configuration><!-- 数据库链接信息 --><connectionStrings><add name="connString" connectionString="Server=127.0.0.1;port=3306;user=root;password=123456;database=studentmanager;"/></connectionStrings></configuration>
此时在 DAL 模块中要使用该配置文件,就需要先在模块引用中添加System.Configuration
引用,然后在类中显式的引用命名空间:
using System.Configuration;
最后就可以使用形如ConfigurationManager.ConnectionStrings["connString"].ToString()
进行对应数据的获取了。
2 用户登录
在项目的整体框架都搭建好之后,就需要理一下程序的流程了,其实也很简单,就是主线程显示登录窗体,输入账号密码,如果正确主程序就打开主界面,错误就返回信息,不登录点击退出就直接退出主线程,如果登录正确的同时还需要保存用户信息。
Program.cs
是程序启动的入口点,即登录窗口体也需要在此处调用显示。此时要注意的是,登录窗体不能作为参数地调用Application.Run()
。因为放置在Application.run()
方法中的窗体就意味着当前窗体作为主线程运行,此时关闭该窗体即整个程序都退出。
同时也要注意到窗体调用show
与showDialog
的区别(《
c# cs项目里面窗体的ShowDialog()和show()的区别》),简单来说,ShowDialog()
弹出的窗体为模式化窗体(此时,之前的窗体为父窗体,当前的窗体为子窗体),show()
弹出的窗体为非模式化窗体,二者的区别:
模式化窗体会使程序中断,直到关闭窗体打开窗体后不能替换到其他窗体子窗体和父窗体互斥,即子窗体打开后无法聚焦到父窗体上返回值不同分别为dialogresult
和void
所以可以在Progarm.cs
可以添加:
using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;using Models;namespace StudentManager{static class Program{// 相当于全局变量public static Admin currentAdmin = null; // 当前用户/// <summary>/// 应用程序的主入口点。/// </summary>[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);// 显示登录窗口FrmUserLogin frmUserLogin = new FrmUserLogin();DialogResult result = frmUserLogin.ShowDialog();// 获取 登录窗口 返回的信息if (result == DialogResult.OK){Application.Run(new FrmMain()); // 主线程窗口}else{Application.Exit(); // 退出整个程序}}}}
待登录窗口中的数据验证之后,即可获取数据库中的数据进行校对,这个逻辑就卸载 DAL 模块之中,然后比校成功之后,就需要修改窗体的返回值DialogResult
,此时可以如以下语句进行修改:
this.DialogResult = DialogResult.OK;
在程序中一旦设置
DialogResult
的值,接下来就会自动执行close()
的方法,所以其实没有必要写this.close()
关闭当前窗体。
同时,还需要保存用户信息,这里保存用户信息的方式是将用户信息设置为全局静态变量,而程序的全局静态变量声明在Program.cs
文件中,在其它的窗体文件可以使用Program.currentUserMsg
的形式进行访问与修改。
3 关于主窗体内嵌子窗体
首先要理解Panel
控件,Windows 窗体Panel
控件用于为其他控件提供可识别的分组(嵌板,就是一个面板容器)。而分组在Panel
里的控件可以通过Panel
的Controls
属性进行访问,该属性返回一组Control
列表,所以还需要强制转换为特定的Form
类型。
主窗体内嵌子窗体的方式就是使用Panel
控件,将子窗体设置到在Panel
的Controls
中,并显示,具体操作如下:
private void openForm(Form formObj){formObj.TopLevel = false; // 将子窗体设置为非顶级控件,作为子窗体内嵌必须formObj.WindowState = FormWindowState.Maximized; // 设置子窗口最大化formObj.FormBorderStyle = FormBorderStyle.None; // 消除子窗口边框this.panel1.Controls.Add(formObj); // 添加到 panel1 中,此时 formObj 的父窗体 parent 已经设置为 panel1formObj.Show(); // 显示子窗体}
关闭内嵌子窗体,如下
private void closeFrom(){// 循环面板 Contorls 列表,将窗体关闭并移出foreach (Control itemOfControl in this.panel1.Controls) {if (itemOfControl is Form){Form formObj = (Form)itemOfControl;formObj.Close();this.panel1.Controls.Remove(itemOfControl);}}}
5 优化用户体验
5.1 窗体的FormClosing
事件
《C# 关于MessageBox.Show()函数》
为了防止用户的误操作,很多时候在关闭窗口时,系统会弹出询问窗口,这就需要使用到FormClosing
事件,窗体在调用Close
方法的时候,都会先执行FormClosing
事件,所以弹出询问窗口的逻辑就可以写在这个事件中(查看窗体的属性,可以在事件列表中找到该事件进行添加),FormClosing
事件有个FormClosingEventArgs
参数,将该参数的Cancel
属性设置为true
即可取消窗体的关闭了。
与此同时还会使用到MessageBox.Show()
,它被设计为弹出提示框,返回一个DialogResult
结果,接受四个参数依次为:
内容标题按键图标默认激活按键
private void FrmMain_FormClosing(object sender, FormClosingEventArgs e){DialogResult dialogResult = MessageBox.Show("是否退出程序", "询问", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);if (dialogResult == DialogResult.Cancel){e.Cancel = true;}}
5.2 使用代码设置背景图片
想要程序好看一点可能需要在某些地方使用以下背景图片,可以直接的在对应的空间属性页面中设置BackgroundImage
属性直接导入图片,也可以在控件的初始化函数中使用代码进行设置,设置控件背景图片属性的类型为Image
类,可以使用Image
类的FromFile
方法从传入对应文件路径,获取对应图片的Image
对象实例,Image
类的命名空间在System.Drawing
,值得注意的是,使用相对路径时,是基于主程序所在文件,如F:\c sharp\StudentManager\StudentManager\bin\Debug
,eg:
this.panel1.BackgroundImage = Image.FromFile("./static/img/mainBackgroundImg.jpg");
5.3 登录窗口检测Enter
按键事件
想要优化的功能就类似使用Tab
按键后,输入框的焦点会下移,此时就需要监听输入控件的按键事件,可以在对应的控件的事件列表中进行添加,按键事件为KeyDown
,其中参数KeyEventArgs
有一个KeyValue
属性用来存储用户输入的按键代码,而Enter
按键的为13
,例如:
private void userName_KeyDown(object sender, KeyEventArgs e){if (this.userName.Text.Length == 0){return;}// 13 为 Enter 按键的代码,如果检测到按键为 Enter,则聚焦密码输入框if (e.KeyValue == 13){this.pw.Focus();}}
如果觉得《C#笔记(学生管理系统实战 - 用户登录)》对你有帮助,请点赞、收藏,并留下你的观点哦!