7.数据的筛选
功能:通过筛选框在datagridview筛选出符合条件的用户
1.修改FrmUserManager.cs代码
(这里插入一下封装函数的快捷键,选择代码之后点左边的小锤子)
private void BindDgv()
{
// 实现筛选功能
string userName = txtUserName.Text.Trim();
int baseTypeId = (int)cbxBase.SelectedValue;
bool isStop = chkIsStop.Checked;
dgvUserAppraisal.AutoGenerateColumns = false;
// 当筛选框BaseType选择查询所有时,Id=0,但数据表中没有BaseTypeId = 0的值
if (baseTypeId == 0)
{
dgvUserAppraisal.DataSource = UserAppraisalBases.GetListJoinAppraisal().FindAll
(m => m.UserName.Contains(userName) && m.IsDel == isStop);
}
else
{
// =>拉姆达表达式,Contains相当于数据库中的like
dgvUserAppraisal.DataSource = UserAppraisalBases.GetListJoinAppraisal().FindAll
(m => m.UserName.Contains(userName) && m.BaseTypeId == baseTypeId && m.IsDel == isStop);
}
}
知识点:Lambda表达式
也是一种委托,委托参数类型。
lambda运算符"=>"的左边列出了需要的参数,右边定义了赋予lambda变量的方法的实现代码。
如果在lambda表达式的实现代码中需要多条语句,多条语句外必须添加花括号和return语句。
通过lambda表达式可以访问lambda表达式块外部的变量,这称为闭包。如果给多个线程使用闭包,了能遇到并发冲突。lambda表达书可以用于类型为委托的任意地方。
2.在按钮点击事件中绑定1的函数
双击搜索按钮
private void btnSearch_Click(object sender, EventArgs e)
{
BindDgv();
}
8.观察者模式与事件触发
观察者模式:
AfterSelect是一个方法,通过FrmMain.designer.cs获取到this.trvMenu.AfterSelect,点击此事件跳转,发现此AfterSelect是一个TreeViewEventHandler的事件,点击TreeViewEventHandler,发现TreeViewEventHandler是一个委托,通过委托生成事件,通过事件监听treeview控件有没有点击,这种设计模式称为观察者模式。
给窗口左侧treeview添加一个事件AfterSelect
private void trvMenu_AfterSelect(object sender, TreeViewEventArgs e)
{
// 第一个参数object sender是treeview本身,第二个参数e是treeview事件
// 三个方法获取当前选中得node
//bool b1 = ((TreeView)sender).SelectedNode == trvMenu.SelectedNode;
//bool b2 = ((TreeView)sender).SelectedNode == e.Node;
// 清除之前存在的背景色和前景色,如果不清除的话,选中第二个菜单,第一个菜单仍为蓝色
foreach (TreeNode node in trvMenu.Nodes)
{
node.BackColor = Color.White;
node.ForeColor = Color.Black;
}
e.Node.BackColor = SystemColors.Highlight;
e.Node.ForeColor = Color.White;
}
9.DataGridView选中行与右键菜单
功能:在用户上点击右键显示菜单:添加编辑和停用,在已停职的用户上点击右键显示菜单:添加编辑和启用,在空白处点击右键显示菜单:添加
1.拖动一个控件ContextMenuStrip
2.先将datagridview的属性ContextMenuStrip修改值选择刚才新建的控件
3.修改datagridview的事件MouseDown
private void dgvUserAppraisal_MouseDown(object sender, MouseEventArgs e)
{
// 判断是否是右键单击
if (e.Button == MouseButtons.Right)
{
tsmAdd.Visible = true;
tsmEdit.Visible = false;
tsmStart.Visible = false;
tsmStop.Visible = false;
}
}
4.修改datagridview的事件CellMouseDown
- 需要鼠标在选中的时候选中一整行,所以将datagrifview的属性SelectionMode属性值修改为FullRowSelect
- 只需要选中一行,不需要选中多行,所以将MultiSelect的值修改为false
- 右键才出现添加编辑等的功能,点击datagridview右上角中的小三角,取消选中启用添加,编辑,删除,这样在鼠标左键点击时就不对表格进行修改
private void dgvUserAppraisal_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if(e.Button == MouseButtons.Right)
{
// 如果e.RowIndex = -1,表示没有选中任何行
if (e.RowIndex > -1)
{
// 鼠标在某行点击右键,表示这行被选中
dgvUserAppraisal.Rows[e.RowIndex].Selected = true;
tsmAdd.Visible = true;
tsmEdit.Visible = true;
tsmStart.Visible = false;
tsmStop.Visible = false;
}
}
}
10.DataGridView单行处理及项目分层
功能:判断在用户上点击右键显示的菜单显示停用还是启用。
1.将表格是否停用这一行的显示形式改成复选框
点击datagridview右上角小三角,编辑列,IsDel属性值ColumnType修改成DataGridViewCheckBoxColumn
2.修改FrmUserManager.cs代码
// 判断右键菜单应该显示启用还是停用
bool isDel = (bool)dgvUserAppraisal.SelectedRows[0].Cells["IsDel"].Value;
if(isDel)
{
tsmStart.Visible = true;
}
else
{
tsmStop.Visible = true;
}
功能:添加用户
3.新建一个窗体FrmSetUser.cs
- 修改窗体属性值FormBorderStyle为FixedToolWindow
- 按照需求修改窗体样式
- 给身份下拉框获取数据库中的身份类型
List<AppraisalBases> appraisalBases = new List<AppraisalBases>();
appraisalBases = AppraisalBases.ListAll();
// 单向数据源绑定
cbxBase.DataSource = appraisalBases;
cbxBase.DisplayMember = "BaseType";
cbxBase.ValueMember = "Id";
- 双击ContextMenuStrip中的添加按钮,把FrmSetUser.cs显示出来
private void tsmAdd_Click(object sender, EventArgs e)
{
FrmSetUser frmSetUser = new FrmSetUser();
frmSetUser.ShowDialog();
}
功能:拆分项目
4.新建一个项目(类库),将/Models文件夹下的两个类移动到新建的Appraisal_Systerm.Models
5.在原有的项目添加引用Appraisal_Systerm.Models
操作步骤:在引用上右键,添加引用
6.同理,提取出Appraisal_Systerm.Utility
C#项目分层的三层架构:
DAL:数据访问层
BLL:业务逻辑层
UI:视图层
11.反射遍历获取的数据并转换成实体
1.在Models项目中新建一个Users.cs类
功能:通过反射获取Users表中的数据
using Appraisal_Systerm.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Appraisal_Systerm.Models
{
public class Users
{
// 属性与数据表Users列的内容一致
public int Id { get; set; }
public string UserName { get; set; }
public string Sex { get; set; }
public string Password { get; set; }
public int BaseTypeId { get; set; }
public bool IsDel { get; set; }
public static List<Users> ListAll()
{
DataTable dt = SqlHelper.ExecuteTable("SELECT u.Id,u.Password,u.BaseTypeId,u.UserName,u.Sex,u.IsDel FROM Users u");
List<Users> users = new List<Users>();
foreach (DataRow dr in dt.Rows)
{
users.Add(dr.DataRowToModel<Users>());
}
return users;
}
}
2.在Utility项目中新建一个ToModel.cs类
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Appraisal_Systerm.Utility
{
public static class ToModel
{
// 扩展方法
public static TModel DataRowToModel<TModel>(this DataRow dr)
{
// 反射:类被封装到一个盒子里,没有办法获取到类,想要获取到类的属性和方法的行为叫反射。
// 泛型反射:想要获取到所有类型类的方法,如果用object就要涉及到拆箱和封箱效率低,所以用泛型。
// this:扩展方法,扩展方法必须在静态类中,扩展方法也必须是一个静态方法。
// 获取泛型方法的类型
Type type = typeof(TModel);
// 获取TModel实例化对象
TModel md = (TModel)Activator.CreateInstance(type);
foreach (var prop in type.GetProperties())
{
prop.SetValue(md,dr[prop.Name]);
}
return md;
}
}
}
反射用的是System.Type类
存储类型的引用:Type t = typeof(double);运算符的参数是类型的名称。
type.GetProperties():用于获取对应数据类型的成员信息。
12.方法扩展及参数化改造
1.为了实现Sql参数化,修改SqlHelper.cs
2.修改Users.cs代码
// 添加
public static int Insert(Users user)
{
// 采用Sql注入,方法是Sql语句参数化
return SqlHelper.ExecuteNonQuery($"INSERT INTO Users(UserName,Password,Sex,BaseTypeId,IsDel) VALUES(@UserName,@Password,@Sex,@BaseTypeId,@IsDel)",
new SqlParameter("@UserName",user.UserName),
new SqlParameter("@Password", user.Password),
new SqlParameter("@Sex", user.Sex),
new SqlParameter("@BaseTypeId", user.BaseTypeId),
new SqlParameter("@IsDel", user.IsDel)
);
}
// 修改
public static int Update(Users user)
{
// 采用Sql注入,方法是Sql语句参数化
int rows = SqlHelper.ExecuteNonQuery($"UPDATE Users SET UserName=@UserName,Password=@Password,Sex=@Sex,BaseTypeId=@BaseTypeId,IsDel=@IsDel WHERE Id=@Id",
new SqlParameter("@Id", user.Id),
new SqlParameter("@UserName", user.UserName),
new SqlParameter("@Password", user.Password),
new SqlParameter("@Sex", user.Sex),
new SqlParameter("@BaseTypeId", user.BaseTypeId),
new SqlParameter("@IsDel", user.IsDel)
);
return rows;
}
13.用户添加及联动刷新
1.用户添加功能,双击保存按钮跳转到方法
private void btnSave_Click(object sender, EventArgs e)
{
string userName = txtUserName.Text.Trim();
int baseTypeId = (int)cbxBase.SelectedValue;
string sex = cbxSex.Text;
bool isDel = chkIsStop.Checked;
Users user = new Users
{
UserName = userName,
BaseTypeId = baseTypeId,
Password = "111",
IsDel = isDel,
Sex = sex
};
Users.Insert(user);
MessageBox.Show("用户添加成功!");
this.Close();
}
2.联动刷新,为了让窗体实现添加完一个用户之后窗体关闭且列表刷新
- 首先在btnSave_Click最后加入
MessageBox.Show("用户添加成功!"); this.Close();
- 在FrmUserManager.cs中加入BindDgv()函数,刷新列表
(模式窗体的特性:当窗体对象调用ShowDialog中,代码卡住不往下执行,关闭模式窗体之后,继续往下执行代码)
14.数据库还原
15.委托的使用与数据的新增响应
功能:点击添加之后datagridview列表自动刷新。
插入一个神奇的快捷键,在VS Code里面填写!+回车,则搭出html框架
委托:
把方法赋值给一个变量,并将这个变量作为一个参数,传递到另一个方法里面去(用js语言举例是因为js是一个弱类型语言,可以把方法赋值给变量)
1.在FrmUserManager.cs中创建一个接受方法的关键字
public delegate void DelBindDgv();// 我们自己声明一个类似string/int关键字
2.声明一个委托变量
DelBindDgv delBindDgv;
3.把方法赋值给委托变量
delBindDgv = BindDgv;
4.在FrmSetUser.cs中重复以上步骤
如果类型为private,则一般命名前方加一个小写的_
private DelBindDgv _delBindDgv;
public FrmSetUser(DelBindDgv delBindDgv)
{
InitializeComponent();
_delBindDgv = delBindDgv;
}