C#窗体应用实战项目——绩效考核管理系统

2023-05-16

笔者入门C#,熟悉C#语法之后,来做一个Winform项目巩固知识,记录一下学习过程。

一、什么是Winform

WinForm 是 Windows Form 的简称,是基于 .NET Framework 平台的客户端(PC软件)开发技术,一般使用C#编程。C# WinForm 编程需要创建「Windows窗体应用程序」项目。
.NET 提供了大量 Windows 风格的控件和事件,可以直接拿来使用,上手简单,开发快速
Windows 窗体应用程序是 C# 语言中的一个重要应用,也是 C# 语言最常见的应用。

二、项目背景

2.1项目介绍

绩效考核管理系统,主要根据企业员工的身份,绩效考核,来综合计算员工的薪资。

2.2涉及知识点

 窗体容器、数据库操作(Sql Server)、数据绑定与获取、委托事件、Sql参数化、泛型反射、反射、分层架构、工厂模式、缓存、泛型缓存、单例模式、动态创建控件。

2.3数据库结构

 本项目主要设计四张表,人员表Users、员工绩效表UserAppraisals、身份基数表AppraisalBases、考核系数表AppraisalCoefficients。表关系如下:

 

2.3.1人员表Users

 存储员工的基本信息,如姓名、性别、密码、身份Id、软删除标记

 

 创建表格SQL语句如下:


GO
/****** Object:  Table [dbo].[Users]    Script Date: 2019/12/19 21:51:04 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Users](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[UserName] [varchar](50) NULL,
	[Sex] [varchar](8) NULL,
	[Password] [varchar](50) NULL,
	[BaseTypeId] [int] NULL,
	[IsDel] [bit] NULL,
 CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

插入数据SQL语句如下: 


INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('张三','男','111','1','False')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('李四','女','111','2','False')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('王五','男','111','3','False')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('赵六1','女','111','4','False')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('田七','男','111','5','False')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('周八','女','111','6','False')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('吴九','女','111','6','True')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('test','男','123456','1','True')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('test2','男','111','1','False')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('test3','男','111','1','False')

INSERT INTO Users(UserName,Sex,Password,BaseTypeId,IsDel) VALUES('test4','男','111','1','False')

2.3.2员工绩效表UserAppraisals

用于记录所有员工的绩效情况,如请假次数,加班次数等

 


GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[UserAppraisals]    Script Date: 2019/12/19 21:51:04 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UserAppraisals](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[UserId] [int] NULL,
	[CoefficientId] [int] NULL,
	[Count] [float] NULL,
	[AssessmentYear] [int] NULL,
	[IsDel] [bit] NULL,
 CONSTRAINT [PK_UserAppraisal] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('1','1','12','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('1','2','2','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('1','3','12','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('1','4','158','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('1','5','36','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('1','6','3','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('3','1','3','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('3','2','3','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('3','3','6','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('3','4','0','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('3','5','116','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('3','6','0','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('5','1','12','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('5','2','12','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('5','3','2','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('5','4','2','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('5','5','2','2018','False')

INSERT INTO UserAppraisals(UserId,CoefficientId,Count,AssessmentYear,IsDel) VALUES('5','6','12','2018','False')

2.3.3身份基数表AppraisalBases

用于记录员工对应身份的基本工资,如政法编制基本工资为20000元;行政编制基本工资为1800元

GO
/****** Object:  Table [dbo].[AppraisalBases]    Script Date: 2019/12/19 21:51:04 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[AppraisalBases](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[BaseType] [varchar](50) NULL,
	[AppraisalBase] [int] NULL,
	[IsDel] [bit] NULL,
 CONSTRAINT [PK_AppraisalBases_1] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

INSERT INTO AppraisalBases(BaseType,AppraisalBase,IsDel) VALUES('政法编制1','20000','False')

INSERT INTO AppraisalBases(BaseType,AppraisalBase,IsDel) VALUES('行政编制','18000','False')

INSERT INTO AppraisalBases(BaseType,AppraisalBase,IsDel) VALUES('事业编制(管理类)','18000','False')

INSERT INTO AppraisalBases(BaseType,AppraisalBase,IsDel) VALUES('事业编制(专业技术类)','19800','False')

INSERT INTO AppraisalBases(BaseType,AppraisalBase,IsDel) VALUES('事业编制(工勤类)','16000','False')

INSERT INTO AppraisalBases(BaseType,AppraisalBase,IsDel) VALUES('社会化用工','8000','False')

2.3.4考核系数表AppraisalCoefficients

存储考核方式对绩效的影响关系,如影响系数,计算方式(-代表扣除工资;+代表奖励工资)


GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[AppraisalCoefficients]    Script Date: 2019/12/19 21:51:04 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[AppraisalCoefficients](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[AppraisalType] [varchar](50) NULL,
	[AppraisalCoefficient] [float] NULL,
	[CalculationMethod] [int] NULL,
	[IsDel] [bit] NULL,
 CONSTRAINT [PK_AppraisalBases] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

INSERT INTO AppraisalCoefficients(AppraisalType,AppraisalCoefficient,CalculationMethod,IsDel) VALUES('请假','0.1','-1','False')

INSERT INTO AppraisalCoefficients(AppraisalType,AppraisalCoefficient,CalculationMethod,IsDel) VALUES('迟到','0.05','-1','False')

INSERT INTO AppraisalCoefficients(AppraisalType,AppraisalCoefficient,CalculationMethod,IsDel) VALUES('加班','0.1','1','False')

INSERT INTO AppraisalCoefficients(AppraisalType,AppraisalCoefficient,CalculationMethod,IsDel) VALUES('办案数量','0.0005','1','False')

INSERT INTO AppraisalCoefficients(AppraisalType,AppraisalCoefficient,CalculationMethod,IsDel) VALUES('维护次数','0.002','1','False')

INSERT INTO AppraisalCoefficients(AppraisalType,AppraisalCoefficient,CalculationMethod,IsDel) VALUES('项目开发','0.3','1','False')

 三、编码

3.1项目创建

右上角 文件-新建-项目,选择C# Windows 桌面选项下的Windows窗体应用(.NET Framework)

 

3.2数据库连接

首先来了解一下C#中using关键词的三个用法:

1.引用命名空间

   类似java的import。可以导入其他文件中的类,而不必指明其详细的命名空间。

   如using System之后,就可以直接用string代替System.string

2.using别名

   给某个详细的命名空间中的某个类型取别名,用于区分不同命名空间中名字相同的类。

   如using test1=A.test;

       using test2=B.test;

3.用来简化资源的释放

   using定义了一个范围,一旦超出了这个范围,自动调用IDisposable释放调该对象资源,

   只有实现了IDisposable的类可以使用这种语法。

   using(SqlConnection conn=new SqlConnection(ConStr))

   using实质是一个try-finally语句,并在finally中调用对象的Dispose方法释放资源,以防程序在出错时,资源得不到释放。

连接数据库操作:

1.编写连接字符串,为了简洁,将连接字符串写在App.config里面

  <connectionStrings>
    <add name="ConStr" connectionString="Data Source=127.0.0.1;database=PerformanceAppraisalDb;uid=sa;pwd=123456"/>
  </connectionStrings>

2.创建SqlConnection对象

namespace Appraisal_System.Utility
{
    public class SqlHelper
    {
        public static string ConStr { get; set; }

        public static DataTable ExecuteTable(string cmdText, params SqlParameter[] sqlParameters)
        {
            using(SqlConnection conn=new SqlConnection(ConStr))
            {
                conn.Open();
                SqlCommand cmd = new SqlCommand(cmdText, conn);
                cmd.Parameters.AddRange(sqlParameters);
                SqlDataAdapter sda = new SqlDataAdapter(cmd);
                DataSet ds = new DataSet();
                sda.Fill(ds);
                return ds.Tables[0];
            }
        }

        public static int ExecuteNonQuery(string cmdText,params SqlParameter[] sqlParameters)
        {
            using (SqlConnection conn = new SqlConnection(ConStr))
            {
                conn.Open();
                SqlCommand cmd = new SqlCommand(cmdText, conn);
                cmd.Parameters.AddRange(sqlParameters);
                int rows = cmd.ExecuteNonQuery();
                if (rows <= 0)
                {
                    //throw new Exception("数据库操作失败");
                }
                return rows;
            }
        }
    }
}

 params修饰可变数组,表示传入的参数个数不定;

 SqlParameter类用来实现带参数的Sql语句,防止Sql注入。该类表示SqlCommand的参数,实际调用时可以通过SqlCommand的Parameters.Add()或AddRange()方法传入Sql参数。

3.3用户管理窗体

窗体元素如下:

先介绍几个常见的窗体元素:

label:是一个标签,用来进行文字说明的

textBox:是一个输入框,输入文字。类似于html中的input标签中的text

comboBox:下拉框,常用于在多个项之间进行选择,如选择城市

checkBox:单选框

dataGridView:数据表格,以表格的形式展现数据

button:按钮

在dataGridView中添加列

编写AppraisalBases充血模型代码

充血模型和贫血模型区别:

充血模型:

  • 数据和对应的业务逻辑被封装到同一个类中。因此,这种充血模型满足面向对象的封装特性,是典型的面向对象编程风格。
  • 业务逻辑集中在 Service 类中。基于充血模型,Service 层包含 Service 类和 Domain 类两部分。Domain 是基于充血模型开发的,既包含数据,也包含业务逻辑。而 Service 类变得非常单薄。
    充血模型中,绝大多业务逻辑都应该被放在domain里面,包括持久化逻辑,而Service层是很薄的一层,仅仅封装事务和少量逻辑,不和DAO层打交道。service :组合服务也叫事务服务;model:除包含get set方法,还包含原子服务和数据持久化的逻辑

贫血模型:

  • 贫血模型是一种领域模型,其中领域对象包含很少或没有业务逻辑。是一种面向过程的编程模式,它与面向对象设计的基本思想相悖,将数据和过程结合在一起。
  • 因为贫血模型没有逻辑实现,所以逻辑基本上会放到调用贫血模型的service中,这些service类会转换领域对象的状态。
  • 贫血模型中,domain包含了不依赖于持久化的原子领域逻辑,而组合逻辑在Service层。service :组合服务,也叫事务服务。model:除包含get set方法,还包含原子服务(如获得关联model的id)。dao:数据持久化。
     

AppraisalBases实体类如下

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Appraisal_System.Utility;
namespace Appraisal_System.Models
{
    public class AppraisalBases
    {
        public int Id { get; set; }
        public string BaseType { get; set; }
        public int AppraisalBase { get; set; }
        public bool IsDel { get; set; }
        
        public static List<AppraisalBases> ListAll()
        {
            List<AppraisalBases> list = new List<AppraisalBases>();
            DataTable dt = SqlHelper.ExecuteTable("SELECT * FROM AppraisalBases");
            foreach (DataRow dr in dt.Rows)
            {
                list.Add(dr.DataRowToModel<AppraisalBases>());
            }
            return list;
        }

        private static AppraisalBases ToModel(DataRow dr)
        {
            AppraisalBases appraisalBase= new AppraisalBases();
            appraisalBase.Id = (int)dr["Id"];
            appraisalBase.BaseType = dr["BaseType"].ToString();
            appraisalBase.AppraisalBase = (int)dr["AppraisalBase"];
            appraisalBase.IsDel = (bool)dr["IsDel"];
            return appraisalBase;
        }

        public static int Update(AppraisalBases appraisal)
        {
            string sql = "UPDATE AppraisalBases SET BaseType=@BaseType,AppraisalBase=@AppraisalBase,IsDel=@IsDel WHERE Id=@Id";
            int rows = SqlHelper.ExecuteNonQuery(sql,
                new SqlParameter("@Id", appraisal.Id),
                new SqlParameter("@BaseType", appraisal.BaseType),
                new SqlParameter("@AppraisalBase", appraisal.AppraisalBase),
                new SqlParameter("@IsDel", appraisal.IsDel)
                );
            return rows;
        }
    }
}

Users实体类如下 

using Appraisal_System.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Appraisal_System.Models
{
    public class Users
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public string PassWord { get; set; }
        public string Sex { get; set; }
        public int BaseTypeId { get; set; }
        public bool IsDel { get; set; }


        public static List<Users> ListAll()
        {
            List<Users> list = new List<Users>();
            string sql= "SELECT u.Id,u.UserName,u.PassWord,u.Sex,u.BaseTypeId,u.IsDel FROM Users u";
            DataTable dt = SqlHelper.ExecuteTable(sql);
            foreach (DataRow dr in dt.Rows)
            {
                list.Add(dr.DataRowToModel<Users>());

            }
            return list;
        }
        public static int Insert(Users user)
        {
            string sql = $"INSERT INTO Users(UserName,PassWord,Sex,BaseTypeId,IsDel) VALUES(@UserName,@PassWord,@Sex,@BaseTypeId,@IsDel)";
            //using SqlParameter to set query params
            return SqlHelper.ExecuteNonQuery(sql,
                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)
        {
            string sql = $"UPDATE Users SET UserName=@UserName,PassWord=@PassWord,Sex=@Sex,BaseTypeId=@BaseTypeId,IsDel=@IsDel WHERE Id=@Id";
            //using SqlParameter to set query params
            return SqlHelper.ExecuteNonQuery(sql,
                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),
                new SqlParameter("@Id", user.Id)
                );
        }
    }

}

整个窗体代码 

using Appraisal_System.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Appraisal_System
{
    public delegate void DelBindDgv();//声明一个类似string/int的关键字DelBindDgv delBindDgv
    public partial class FrmUserManager : Form
    {
        DelBindDgv delBindDgv;
        public FrmUserManager()
        {
            InitializeComponent();
        }

        private void FrmUserManager_Load(object sender, EventArgs e)
        {
            BindCbx();
            BindDgv();
            delBindDgv = BindDgv;
        }

        private void BindDgv()
        {
            string userName = txtUserName.Text.Trim();
            int baseTypeId = (int)cbxBase.SelectedValue;
            bool isStop = chkIsStop.Checked;
            List<UserAppraisalBases> userAppraisalBases = UserAppraisalBases.GetListJoinAppraisal();
            dgvUserAppraisal.AutoGenerateColumns = false;
            if (baseTypeId == 0)
            {
                dgvUserAppraisal.DataSource = userAppraisalBases.FindAll
                (m => m.UserName.Contains(userName) && m.IsDel == isStop);
            }
            else
            {
                dgvUserAppraisal.DataSource = userAppraisalBases.FindAll
                (m => m.UserName.Contains(userName) && m.BaseTypeId == baseTypeId && m.IsDel == isStop);
            }
        }

        private void BindCbx()
        {
            List<AppraisalBases> appraisalBases = new List<AppraisalBases>();
            //add an initial choice for "querying all"
            appraisalBases.Add(new AppraisalBases
            {
                Id = 0,
                BaseType = "-查询所有-",
                AppraisalBase = 0,
                IsDel = false
            });

            appraisalBases.AddRange(AppraisalBases.ListAll());
            //set dataSource = appraisalBases which queried 
            cbxBase.DataSource = appraisalBases;
            //DisplayMember means what we see on the framework
            cbxBase.DisplayMember = "BaseType";
            //ValueMember means its value such as Id;
            cbxBase.ValueMember = "id";

            /*cbxBase.Text = "-查询所有-";
            cbxBase.Items.Add("-查询所有-");
            foreach (var appraisalBase in appraisalBases)
            {
                cbxBase.Items.Add(appraisalBase.BaseType);
            }*/
        }



        private void button1_Click(object sender, EventArgs e)
        {
            BindDgv();
        }

        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;
            }
        }

        private void dgvUserAppraisal_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (e.RowIndex > -1)
                {
                    dgvUserAppraisal.Rows[e.RowIndex].Selected = true;
                    tsmAdd.Visible = true;
                    tsmEdit.Visible = true;

                    bool IsDel = (bool)dgvUserAppraisal.SelectedRows[0].Cells["IsDel"].Value;
                    if (IsDel)
                    {
                        tsmStart.Visible = true;
                    }
                    else
                    {
                        tsmStop.Visible = true;
                    }

                }
            }
        }

        private void tsmAdd_Click(object sender, EventArgs e)
        {
            FrmSetUser frmSetUser=new FrmSetUser(delBindDgv);
            frmSetUser.ShowDialog();
            //Reload bindDgv data to refresh the latest data which was inserted just now
            BindDgv();
        }

        private void tsmEdit_Click(object sender, EventArgs e)
        {
            int userId = (int)dgvUserAppraisal.SelectedRows[0].Cells["Id"].Value;
            FrmSetUser frmSetUser = new FrmSetUser(delBindDgv,userId);
            frmSetUser.ShowDialog();
        }
    }
}

 编写用户管理窗体右键事件,出现新建、编辑、启用、停用子菜单

子菜单元素为ContextMeauStrip

 

新建、编辑窗体 

using Appraisal_System.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Appraisal_System
{
    public partial class FrmSetUser : Form
    {
        private DelBindDgv _delBindDgv;
        public FrmSetUser(DelBindDgv delBindDgv)
        {
            InitializeComponent();
            _delBindDgv = delBindDgv;
        }
        private Users _user;
        public FrmSetUser(DelBindDgv delBindDgv,int userId):this(delBindDgv)
        {
            //:this(args) like java this(args) but in C# should be after method and java in method
            _user = Users.ListAll().Find(m => m.Id == userId);

        }
        private void FrmSetUser_Load(object sender, EventArgs e)
        {
            List<AppraisalBases> appraisalBases = new List<AppraisalBases>();
            //add an initial choice for "querying all"
            appraisalBases.AddRange(AppraisalBases.ListAll());
            //set dataSource = appraisalBases which queried 
            cbxBase.DataSource = appraisalBases;
            //displayMember means what we see on the framework
            cbxBase.DisplayMember = "BaseType";
            //displayMember means its value such as Id;
            cbxBase.ValueMember = "Id";

            //load the user which is checked now
            if (_user != null)
            {
                txtUserName.Text = _user.UserName;
                cbxBase.SelectedValue = _user.BaseTypeId;
                cbxSex.Text = _user.Sex;
                chkIsStop.Checked = _user.IsDel;
            }
        }

        private void btnmSave_Click(object sender, EventArgs e)
        {
            string userName = txtUserName.Text.Trim();
            int baseTypeId = (int)cbxBase.SelectedValue;
            string sex = cbxSex.Text;
            bool isDel = chkIsStop.Checked;

            if (_user == null)
            {
                Users user = new Users
                {
                    UserName = userName,
                    BaseTypeId = baseTypeId,
                    IsDel = isDel,
                    Sex = sex,
                    PassWord = "111",
                };
                Users.Insert(user);
                MessageBox.Show("用户添加成功!");
            }
            else
            {
                _user.UserName = userName;
                _user.BaseTypeId = baseTypeId;
                _user.IsDel = isDel;
                _user.Sex = sex;
                Users.Update(_user);
                MessageBox.Show("用户修改成功!");
            }
            _delBindDgv(); 
            this.Close();
        }
    }
}

FrmSetUser中用到了委托机制。委托简而言之,就是将某个类的某个方法委托给其他类执行,需要Delegate关键字。

委托四部曲

1、声明委托类型

2、有一个方法包含了执行的代码

3、创建委托实例

4、调用委托实例

父类将委托对象作为构造方法中的参数传递给子类

 子类在创建的时候调用自己的构造方法,绑定委托对象。子类就可以在自己内部,调用该方法。

因为子窗体是用来新建和编辑用户的,那么子窗体在提交的时候,需要进行表单的数据刷新,而表单的数据刷新是由父窗体中的BindDgv方法完成的。子窗体通过调用委托,实现了间接调用了父窗体中BindDgv的方法。

3.4基数管理窗体

工厂模式+反射+泛型缓存优化窗体的创造

场景:左侧树形菜单点击进行窗体切换时,先前都是每切换一次,就新建一个窗体,复用性差,性能低下。

解决方案:将窗体的创造交给FormFactory工厂类去执行,且每个窗体设计成单例模式,缓存在List<Form>中。创造窗体时,利用反射创造,即根据传入的窗体类名,创造出对应的窗体类。

Assembly关键词:

通过Assembly可以动态加载程序集,并查看程序集的内部信息,其中最常用的就是Load()这个方法。
     Assembly assembly=Assembly.Load("MyAssembly");
     利用Assembly的object CreateInstance(string) 方法可以反射创建一个对象,参数0为类名。

Type关键词:

     Type是最常用到的类,通过Type可以得到一个类的内部信息,也可以通过它反射创建一个对象。一般有三个常用的方法可得到Type对象。

Activator关键词:

     需要动态的创建一个实例模型的时候,就用Activator.CreateInstance(Type type)

     以下两种方法区别仅为:创建无参数的构造方法和创建有参数的构造函数。

1. Activator.CreateInstance (Type)

2. Activator.CreateInstance (Type, Object[])

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Appraisal_System.Common
{
    public class FormFactory
    {
        //single instance
        private static Form form;
        private static List<Form> forms = new List<Form>();
        private static List<Type> types;
        static FormFactory()
        {
            Assembly ass = Assembly.LoadFrom("Appraisal_System.exe");
            types = ass.GetTypes().ToList();
        }
        public static Form CreateForm(string formName)
        {
            //get by reflecting by name of c#
            //Assembly ass=Assembly.Load("Appraisal_System");
            //get by path LoadFile of absolute path or LoadFrom of current path
            //string path = AppDomain.CurrentDomain.BaseDirectory;
            //Assembly ass1 = Assembly.LoadFile(path + "Appraisal_System.exe");
            HideFormAll();
            formName = formName == null ? "FrmNone" : formName;
            Form form= forms.Find(m=>m.Name==formName);
            //avoid to create the same form too many times by checking the forms
            if (form == null)
            {
                Type type = types.Find(m => m.Name == formName);
                form =(Form)Activator.CreateInstance(type);
                forms.Add(form);
            }
            return form;
        }
        public static void HideFormAll()
        {
            foreach (Form f in forms)
            {
                f.Hide();
            }
        }
    }
}

基数管理窗体的实现代码

using Appraisal_System.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Appraisal_System
{
    public partial class FrmBaseManager : Form
    {
        public FrmBaseManager()
        {
            InitializeComponent();
        }

        private void FrmBaseManager_Load(object sender, EventArgs e)
        {
            dgvBase.DataSource = AppraisalBases.ListAll();
        }

        private void dgvBase_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            AppraisalBases appraisal=(AppraisalBases)dgvBase.Rows[e.RowIndex].DataBoundItem;
            AppraisalBases.Update(appraisal);
        }
    }
}

3.5系数管理窗体

3.6人员绩效窗体

人员绩效窗体是用来显示所有员工的绩效明细。包括所有考核项,以及年终奖。

 子窗体,用来编辑考核项

观察表中,可知任何一个考核项,如请假、迟到、加班都会影响实发年终奖。而每个考核项有考核名称、系数、次数、计算方式。根据需求(系数、次数、计算方式)这些是隐藏不显示在表格中的,利用表格横向拓展来填充表格。

基本表:在此表上做横向拓展。

SELECT u.Id,u.UserName,u.Sex,u.BaseTypeId,a.BaseType,a.AppraisalBase,u.IsDel FROM Users u LEFT JOIN AppraisalBases a ON u.BaseTypeId=a.Id

其次,需要知道每个员工的各项考核项情况。将UserAppraisals表和AppraisalCoefficients联表查询。

 那么只要我们在上述表中对UserId和AssessmentYear筛选,就可以知道指定用户在某一年的所有考核项情况。如对于UserId=1的员工和AssessmentYear=2018情况如下:

可以看到UserId=1的员工在2018年,请假了16次,迟到2次,加班3次等等。根据这些就可以计算得出该用户在某年的总年终奖。 

 上述两个实体类AppraisalCoefficients以及UserAppraisalCoefficients代码如下:

using Appraisal_System.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Appraisal_System.Models
{
    public  class AppraisalCoefficients
    {
        public int Id { get; set; }
        public string AppraisalType { get; set; }
        public double AppraisalCoefficient { get; set; }
        public int CalculationMethod { get; set; }
        public bool IsDel { get; set; }

        public static List<AppraisalCoefficients> ListAll()
        {
            List<AppraisalCoefficients> list=new List<AppraisalCoefficients>();
            DataTable dt = SqlHelper.ExecuteTable("SELECT * FROM AppraisalCoefficients");
            foreach (DataRow dr in dt.Rows)
            {
                list.Add(dr.DataRowToModel<AppraisalCoefficients>());
            }
            return list;
        }
    }
}

using Appraisal_System.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Appraisal_System.Models
{
    public class UserAppraisalCoefficients
    {
        public int Id { get; set; }
        public int UserId { get; set; }
        public int CoefficientId { get; set; }
        public double Count { get; set; }
        public int AssessmentYear { get; set; }
        public string AppraisalType { get; set; }
        public double AppraisalCoefficient { get; set; }
        public int CalculationMethod { get; set; }
        public bool IsDel { get; set; }

        public static List<UserAppraisalCoefficients> ListAll()
        {
            List<UserAppraisalCoefficients> list=new List<UserAppraisalCoefficients>();
            string sql = "SELECT ua.*,ap.AppraisalType,ap.AppraisalCoefficient,ap.CalculationMethod FROM UserAppraisals ua LEFT JOIN AppraisalCoefficients ap ON ua.CoefficientId=ap.Id";
            DataTable dt=SqlHelper.ExecuteTable(sql);
            foreach (DataRow dr in dt.Rows)
            {
                list.Add(dr.DataRowToModel<UserAppraisalCoefficients>());
            }
            return list;
        }
    }
}

 表横向拓展代码以及完整窗体代码如下:

using Appraisal_System.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Appraisal_System
{
    public partial class FrmUserAppraisal : Form
    {
        public FrmUserAppraisal()
        {
            InitializeComponent();
        }
        Action bindDgv;
        private void FrmUserAppraisal_Load(object sender, EventArgs e)
        {
            SetCol();
            BindDgvUserAppraisal();
            //委托
            bindDgv = BindDgvUserAppraisal;
        }

        private void BindDgvUserAppraisal()
        {
            //get the form which need extending
            DataTable dtUser = UserAppraisalBases.GetDtJoinAppraisal();
            //get the coefficient form to extend the main form
            List<AppraisalCoefficients> appraisalCoefficients = AppraisalCoefficients.ListAll();
            //fill the dtUser by the coefficient form
            foreach (var item in appraisalCoefficients)
            {
                //add the name of coefficient
                dtUser.Columns.Add(new DataColumn
                {
                    ColumnName = "AppraisalType" + item.Id
                });
                //add the value of coefficient
                dtUser.Columns.Add(new DataColumn
                {
                    ColumnName = "AppraisalCoefficient" + item.Id
                });
                //add the calculationMethod
                dtUser.Columns.Add(new DataColumn
                {
                    ColumnName = "CalculationMethod" + item.Id
                });
            }
            //add the assessmentYear
            dtUser.Columns.Add(new DataColumn
            {
                ColumnName = "AssessmentYear"
            });
            //add the YearBonus
            dtUser.Columns.Add(new DataColumn
            {
                ColumnName = "YearBonus"
            });
            //fill the dtUser
            List<UserAppraisalCoefficients> userAppraisalCoefficients = UserAppraisalCoefficients.ListAll();
            for (int i = 0; i < dtUser.Rows.Count; i++)
            {
                var uacFilter = userAppraisalCoefficients.FindAll(m => m.UserId == (int)dtUser.Rows[i]["Id"] && m.AssessmentYear == Convert.ToInt32(cbxYear.Text));
                //the array of coefficients to calculation
                double[] yearBonusArray = new double[uacFilter.Count];
                for (int j = 0; j < uacFilter.Count; j++)
                {
                    //get AppraisalType对应的dtUser的ColumnName的值
                    //get Appraisal count
                    string appraisalTypeKey = "AppraisalType" + uacFilter[j].CoefficientId;
                    double appraisalTypeCountValue = uacFilter[j].Count;
                    //get Appraisal coefficient
                    string appraisalCoefficientKey = "AppraisalCoefficient" + uacFilter[j].CoefficientId;
                    double appraisalCoefficientValue = uacFilter[j].AppraisalCoefficient;
                    //get Appraisal CalculationMethod
                    string calculationMethodKey = "CalculationMethod" + uacFilter[j].CoefficientId;
                    int calculationMethodValue = (int)uacFilter[j].CalculationMethod;
                    //bind to dtUser
                    dtUser.Rows[i][appraisalTypeKey] = appraisalTypeCountValue;
                    dtUser.Rows[i][appraisalCoefficientKey] = appraisalCoefficientValue;
                    dtUser.Rows[i][calculationMethodKey] = calculationMethodValue;

                    //calculation the coefficient
                    //count*coefficient*method
                    yearBonusArray[j] = appraisalCoefficientValue * calculationMethodValue * appraisalTypeCountValue;
                }
                dtUser.Rows[i]["AssessmentYear"] = cbxYear.Text;
                //calculation the final bonus
                double yearBonusAll = 1;
                for (int j = 0; j < yearBonusArray.Length; j++)
                {
                    yearBonusAll += yearBonusArray[j];
                }
                double yearBonusSum = yearBonusAll * Convert.ToDouble(dtUser.Rows[i]["AppraisalBase"]);
                if (yearBonusSum < 0)
                {
                    yearBonusSum = 0;
                }
                dtUser.Rows[i]["YearBonus"] = yearBonusSum;
            }
            dgvUserAppraisal.AutoGenerateColumns = false;
            dgvUserAppraisal.DataSource = dtUser;
        }

        private void SetCol()
        {
            List<AppraisalCoefficients> appraisalCoefficients = AppraisalCoefficients.ListAll();
            List<DataGridViewTextBoxColumn> dataGridViewTextBoxColumns = new List<DataGridViewTextBoxColumn>();
            foreach (var coe in appraisalCoefficients)
            {
                dataGridViewTextBoxColumns.Add(new DataGridViewTextBoxColumn
                {
                    HeaderText = coe.AppraisalType,
                    Name = "AppraisalType" + coe.Id.ToString(),
                    DataPropertyName = "AppraisalType" + coe.Id.ToString(),
                    ReadOnly = true,
                    Width = 88,
                });
                dataGridViewTextBoxColumns.Add(new DataGridViewTextBoxColumn
                {
                    HeaderText = "系数",
                    Name = "AppraisalCoefficient" + coe.Id.ToString(),
                    DataPropertyName = "AppraisalCoefficient" + coe.Id.ToString(),
                    ReadOnly = true,
                    Visible = false,
                    Width = 88,
                });
                dataGridViewTextBoxColumns.Add(new DataGridViewTextBoxColumn
                {
                    HeaderText = "计算方式",
                    Name = "CalculationMethod" + coe.Id.ToString(),
                    DataPropertyName = "CalculationMethod" + coe.Id.ToString(),
                    ReadOnly = true,
                    Visible = false,
                    Width = 88,
                });
            }
            dgvUserAppraisal.Columns.AddRange(dataGridViewTextBoxColumns.ToArray());
            dgvUserAppraisal.Columns.Add(new DataGridViewTextBoxColumn
            {
                HeaderText = "考核年度",
                Name = "AssessmentYear",
                DataPropertyName = "AssessmentYear",
                ReadOnly = true,
                Width = 166
            });
            dgvUserAppraisal.Columns.Add(new DataGridViewTextBoxColumn
            {
                HeaderText = "实发年终奖",
                Name = "YearBonus",
                DataPropertyName = "YearBonus",
                ReadOnly = true,
                Width = 166
            });
        }

        private void dgvUserAppraisal_MouseDown(object sender, MouseEventArgs e)
        {
            tsmEdit.Visible= false;
        }

        private void dgvUserAppraisal_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if(e.Button == MouseButtons.Right)
            {
                if(e.RowIndex > -1)
                {
                    dgvUserAppraisal.ClearSelection();
                    dgvUserAppraisal.Rows[e.RowIndex].Selected = true;
                    tsmEdit.Visible = true;

                }
            }
        }

        private void tsmEdit_Click(object sender, EventArgs e)
        {
            string year=cbxYear.Text;
            int userId = (int)dgvUserAppraisal.SelectedRows[0].Cells["Id"].Value;
            FrmUserAppraisalEdit frmUserAppraisalEdit = new FrmUserAppraisalEdit(userId,year,bindDgv);
            frmUserAppraisalEdit.ShowDialog();
        }
    }
}

编辑考核项子窗体:利用FlowLayoutPanel以及Panel容器动态创造

这个子窗体也用到了委托机制,用于再修改后刷新用户考核项情况。

 

using Appraisal_System.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Appraisal_System
{
    public partial class FrmUserAppraisalEdit : Form
    {
        private int _userId;
        private string _year;
        private Action _bindDgv;
        public FrmUserAppraisalEdit()
        {
            InitializeComponent();
        }

        public FrmUserAppraisalEdit(int userId,string year,Action bindDgv):this()
        {
            _userId = userId;
            _year = year;
            _bindDgv = bindDgv;
        }
        private void btnSave_Click(object sender, EventArgs e)
        {
            var flCtrs = flp.Controls;
            foreach (Control flCtr in flCtrs)
            {
                if (flCtr is Panel)
                {
                    var plCtrs = flCtr.Controls;
                    foreach (var plCtr in plCtrs)
                    {
                        if (plCtr is TextBox)
                        {
                            int acId = Convert.ToInt32(((TextBox)plCtr).Name.Split('_')[1]);
                            double count = Convert.ToDouble(((TextBox)plCtr).Text);
                            UserAppraisals.Delete(_userId, _year, acId);
                            UserAppraisals userAppraisals = new UserAppraisals
                            {
                                UserId = _userId,
                                CoefficientId = acId,
                                AssessmentYear = Convert.ToInt32(_year),
                                Count = count,
                                IsDel = false,
                            };
                            UserAppraisals.Insert(userAppraisals);
                        }
                    }
                }
            }
            MessageBox.Show("修改成功!");
            _bindDgv();
            this.Close();
        }

        private void FrmUserAppraisalEdit_Load(object sender, EventArgs e)
        {
            CreateContorls();
            BindControls();
        }

        private void BindControls()
        {
            List<UserAppraisals> userAppraisals = UserAppraisals.ListByUserIdAndYear(_userId, _year);
            foreach (var ua in userAppraisals)
            {
                var flCtrs = flp.Controls;
                foreach (Control flCtr in flCtrs)
                {
                    if (flCtr is Panel)
                    {
                        var plCtrs = flCtr.Controls;
                        foreach (var plCtr in plCtrs)
                        {
                            if (plCtr is TextBox)
                            {
                                int acId = Convert.ToInt32(((TextBox)plCtr).Name.Split('_')[1]);
                                if (acId == ua.CoefficientId)
                                {
                                    ((TextBox)plCtr).Text = ua.Count.ToString();
                                }
                            }
                        }
                    }
                }
            }
        }

        private void CreateContorls()
        {
            List<AppraisalCoefficients> appraisalCoefficients = AppraisalCoefficients.ListAll();
            foreach (var ac in appraisalCoefficients)
            {
                Panel panel = new Panel();

                Label label = new Label
                {
                    Text = ac.AppraisalType,
                    Width = 60,
                    Location = new Point(0, 4),
                };
                TextBox txt = new TextBox
                {
                    Location = new Point(66, 0),
                    Width = 120,
                    Height = 26,
                    Name="txtAppraisalType_"+ac.Id,
                };
                panel.Controls.Add(label);
                panel.Controls.Add(txt);
                flp.Controls.Add(panel);
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#窗体应用实战项目——绩效考核管理系统 的相关文章

  • 二极管反向恢复过程详细解析

    二极管反向恢复过程 xff0c 现代脉冲电路中大量使用晶体管或二极管作为开关 或者使用主要是由它们构成的逻辑集成电路 而作为开关应用的二极管主要是利用了它的通 电阻很小 断 电阻很大 特性 即二极管对正向及反向电流表现出的开关作用 二极管和
  • 性能优化总结

    性能优化关注点 从图中可以看出 xff0c 性能优化的主要关注 xff1a CPU 内存 磁盘IO 网络IO等四个方面 性能指标 每个关注点都有对应的指标 xff0c 吞吐率 响应时间 QPS IOPS TP99 资源使用率是我们经常关注的
  • Python:优先队列的使用及类的自定义比较函数

    Priority queue模块 该模块定义的优先级队列 xff0c 其内部使用了 heapq 模块 xff0c 所以它的时间复杂度和heapq是相同的 当一个对象的所有元素都是可比较的时 xff0c 默认情况下是根据队列中的对象的第一个元
  • 「STM32入门」USART串口通信

    通信 通信的目的 xff1a 将一个设备的数据传送到另一个设备 xff0c 扩展硬件系统 通信协议 xff1a 制定通信的规则 xff0c 通信双方按照协议规则进行数据收发 STM32常见的通信协议 本文将介绍USART 概念解释 TX R
  • 「数字信号处理」采样过程与内插恢复完整图解

    内插与采样的关系 来源 xff1a 数字信号处理 采样与内插 DSP期末知识点题型4 哔哩哔哩 bilibili
  • 配置vscode作为STM32代码的编辑器(替代keil5)。实现:代码自动补全, 编译,下载。nRF52也可以编译。

    STM32CubeMX新建好工程在工程根目录新建文件夹 vscode在 vscode 文件夹内新建文件c cpp properties json 34 configurations 34 34 name 34 34 STM32 34 任意的
  • Python中的字典

    1 字典概念 Python内置的数据结构之一 xff0c 与列表一样是一个可变序列 以键值对的方式存储数据 xff0c 字典是一个无序的序列 xff08 列表是有序的 xff09 字典通过计算key的hash值确定存储位置 xff0c 所以
  • docker中使用cuda

    需要注意的事项 1 注意应用NVIDIA在docker hub上提供的镜像 本次使用的是 nvidia cuda 10 1 cudnn7 devel ubuntu18 04 2 在宿主机安装 nvidia docker2 3 运行时 要加
  • Mysql8.0 忘记密码怎么办

    Mysql8 0 忘记密码怎么办 今天晨雨帮身边小伙伴解决了mysql8 0无法连接上的问题 中间碰到的一些问题和大家分享一下 跳过密码登录时不成功修改密码时不成功navicat连接时报 2000的问题 1 首先先停止mysql服务 可通过
  • Kurento实战之二:快速部署和体验,Java笔试题编程题

    GitCommit 269548fa27e0089a8b8278fc4fc781d7f65a939b runc Version 1 0 0 rc92 GitCommit ff819c7e9184c13b7c2607fe6c30ae19403
  • QT使用render时pixmap背景不为透明的解决办法

    当我们需要将一个界面绘制成图片时 xff0c 就需要使用到render方法 QPixmap pixmap pwidget gt size pwidget gt render amp pixmap 如果pwidget背景为透明时 xff0c
  • 【iOS】—— 高德地图SDK基础使用

    最近稍微学了学iOS调用高德的SDK xff0c 就随便做做笔记 注意 xff1a 本篇博客基于高德地图SDK的3D地图来写的 xff0c 若使用的是2D地图可能有的方法可能有所不同 xff0c 比如自定义定位蓝点之类的 一 准备工作 xf
  • 如何做代码Code Review

    预防胜于治疗 xff0c 研究表明高效的 Code Review 可以发现70 90 的 bug xff0c Review 作用如下 xff1a 提高团队代码标准 xff0c 所有人共享同一套标准 xff0c 阻止破窗效应 推动团队合作 r
  • 【iOS】—— 浅谈UISearchController

    UISearchController是iOS的一个系统的搜索控件 xff0c 在平时我们输入信息的时候会出现相应的联想搜索的内容 xff0c 然后通过UITableView展示到搜索框的下面 xff0c 供我们选择 原本还想用UITextF
  • Linux Shell中的正则表达式

    Linux Shell中的正则表达式 正则表达式是什么正则表达式通配符 cut命令awk命令sedsort排序命令wc统计命令 正则表达式是什么 正则表达式是用于描述字符排列和匹配模式的一种语法规则 它主要用于字符串的模式分割 匹配 查找及
  • 【Linux】刚烧录完(相当于是第1次连接),VNC树莓派无法连接

    文章目录 解决方法如下 xff1a 1 在Terminal中输入 96 vncserver 96 2 在Terminal中再输入 96 sudo raspi config 96 3 输入连接即可 刚烧录完 xff0c 然后用 ifconfi
  • QT 配置Opencv+gdal心得

    本人研究僧一枚 xff0c 老师给了使用QT开发遥感图像相关程序的课题 xff0c 完全从零开始学习 xff0c 查阅了许多的资料 xff0c 过程里东拼西凑 xff0c 碰壁无数 所以我就想写一些学习的心得体会 xff0c 给自己复习使用
  • Flink 从 kafka 中读取数据并输出到 kafka

    Kafka 是一个分布式的基于发布 订阅的消息系统 xff0c 本身处理的也是流式数据 kafka和flink二者被称为当前处理流式数据的双子星 下面我们将从以下几个步骤展开讲解 xff1a 目录 一 添加maven依赖 二 编写flink
  • 视图创建与管理实验

    xff08 一 xff09 在job数据库中 xff0c 有聘任人员信息表 xff1a Worklnfo表 xff0c 其表结构如下表所示 xff1a create table workinfo id int 4 not null uniq
  • LaTeX的篇章结构

    LaTeX的篇章结构 一般在撰写一个文档时 xff0c 总是先写出文章的提纲 然后根据该提纲进行展开 xff0c 来撰写其他的内容 文章目录 构建小节构建段落标题格式带章节大纲文档目录 构建小节 xff08 1 xff09 用section

随机推荐

  • LaTeX中的参考文献BibLaTeX

    LaTeX中的参考文献BibLaTeX 文章目录 一 介绍二 配置三 参考文献数据库文件四 引用文献1 导入宏包2 添加参考文献数据库3 不同方式引用参考文献4 输出参考文献列表5 编译执行6 修改标题7 列出没有引用的参考文献8 更多样式
  • 独立按键控制LED亮灭

    目录 一 独立按键 二 独立按键控制LED亮灭 三 按键的抖动 四 独立按键控制LED显示二进制 五 独立按键控制LED移位 一 独立按键 轻触按键 xff1a 相当于一种电子开关 xff0c 按下时开关接通 xff0c 松开时开关断开 x
  • 内网权限维持

    权限维持 以下测试均在win7 拓展方面 windows开启rdp 1 设置远程桌面端口 xff08 可以不用输 xff0c 直接第二步 xff0c 默认开启3389 xff09 reg add 34 HKLM System Current
  • 常见优秀代码汇总

    汇总常见的编程习惯 1 语义简单明确 含义 xff1a 写代码时考虑读者 xff0c 优先采取易于读者理解的写法 define THROTL UNSET 2 define THROTL NO LIMIT 1 bool throttle is
  • 2021/7/20

    8 xff1a 30 9 xff1a 00 学习打卡 9 xff1a 30 13 xff1a 00 二招刷题 15 xff1a 00 19 xff1a 00 二招刷题 1 xff0c a题 给你一个长度为N的序列 xff0c 现在需要把他们
  • python可安装软件的制作

    一 生成可执行文件 xff08 exe 安装打包工具pyinstaller 第一种 xff1a 通过win 43 R打开cmd直接使用下面的命令安装即可 pip install pyinstaller 第二种 xff1a 下载pyinsta
  • 汇编常见指令

    文章目录 常见的运算类汇编指令add指令sub指令mul乘法指令div除法指令inc xff08 自增 xff09 xff08 即C语言 43 43 xff09 dec xff08 自减 xff09 xff08 即 xff09 push x
  • 使用阿里云服务器三分钟搭建网站

    目录 一 购买服务器 二 配置云服务器 三 下载XShell编辑器 四 使用XShell与服务器建立连接 五 安装宝塔 六 配置宝塔 七 配置多个站点 一 购买服务器 注意一定要购买CentOS内核的服务器 二 配置云服务器 购买云服务器之
  • STM32 ---寄存器点灯

    1 创建工程 处理器执行程序的时候怎么执行 处理器执行程序都是先执行汇编程序 xff0c 然后在汇编程序里面跳到主函数里面 xff0c 所以要先写好汇编程序 不过这个一般官方提供了 xff0c 只需把这个文件拷到我们的工程文件夹里面 接着将
  • QMessageBox 方法大全,各种弹窗的方法

    QMessageBox Ok xff1a 显示一个OK按钮 xff1b QMessageBox Open xff1a 显示一个打开文件的按钮 xff1b QMessageBox Save xff1a 显示一个保存文件的按钮 xff1b QM
  • 【Python实现视频转文字操作】

    一 安装moviepy模块 1 如果你用的PyCharm 导包的时候报错后 可以直接按Alt 43 Shift 43 Enter install moviepy 2 也可以在终端输入 pip install moviepy 前提是安装好了p
  • 谈论flutter和jetpack compose学习优先级的背后,Android开发有着怎样的一套进阶逻辑?

    前言 xff1a 在1982年的原版电影 银翼杀手 中 xff0c 人类已经发展出了一种人造的生命形式 xff0c 很难将它们与人类区分开来 这些 复制品 被用于危险的工作 xff0c 当它们开始反抗人类主人时 xff0c 一种被称为 刀锋
  • Android中的广播机制

    说明 xff1a 本文是郭霖 第一行代码 第3版 的读书笔记 6 1 广播机制简介 Android中的广播分为两种类型 xff1a 标准广播和有序广播 标准广播 xff1a 完全异步执行的广播 xff0c 在广播发出后 xff0c 所有的B
  • 各种常用默认的端口号

    端口号的范围是从1 xff5e 65535 其中1 xff5e 1024是被RFC 3232规定好了的 xff0c 被称作 众所周知的端口 Well Known Ports xff1b 从1025 xff5e 65535的端口被称为动态端口
  • 序号的结构层次顺序

    数字序号的级别顺序为 xff1a 第一层为汉字数字加顿号 xff0c 例如 xff1a 一 二 三 xff1b 第二层为括号中包含汉字数字 xff0c 例如 xff1a xff08 一 xff09 xff08 二 xff09 xff08 三
  • Abaqus双层混凝土梁三点抗弯(Explicit显式动力学)

    建模过程 1 part 部分 建立两层混凝土棱柱体和三个圆柱体 xff0c 并赋予材料属性 2 装配part xff0c 并在三个圆柱体圆心设立参考点 3 创建分析步 step中创建Dynamic Explicit Time period
  • Linux—生成随机密码

    Linux 小技巧 当我们需要设置十几位长度的密码时 xff0c 可能需要想半天 其实我们可以利用工具来直接生成随机的密码字符串 xff0c 这样又安全又方便 1 urandom 命令 span class token punctuatio
  • MySQL基础学习

    文章目录 MySQL基础学习1 数据库基本操作2 数据的查询2 2 1数据插入2 2 2 单表查询2 2 3 order by语句2 2 4 聚集函数 xff08 aggregate functions xff09 2 2 5 连接查询2
  • C++ 快速读入输出模板(竞赛专用)

    快输快读 xff0c 在算法竞赛中 xff0c 一定程度上可以减小程序的运行时间 xff1a 快读模板1 xff1a inline int read char c 61 getchar int x 61 0 f 61 1 for isdig
  • C#窗体应用实战项目——绩效考核管理系统

    笔者入门C xff0c 熟悉C 语法之后 xff0c 来做一个Winform项目巩固知识 xff0c 记录一下学习过程 一 什么是Winform WinForm 是 Windows Form 的简称 xff0c 是基于 NET Framew