〇、上位机,分层架构
界面层
要实现的功能:
展示数据
获取数据
发送数据
数据层
要实现的功能:
转换数据
打包数据
存取数据
通信层
要实现的功能:
打开连接
关闭连接
读取数据
写入数据
实体类
作用:
封装数据、传递数据
工具类
一、通信介绍及简单测试
一、PLC (Programmable Logic Controller | 可编程逻辑控制器)
简介:
PLC的英文全称是"Programmable Logic Controller",中文称为“可编程逻辑控制器”。这是一种数字运算操作电子系统,专为在工业环境下应用而设计。它采用可编程存储器,用来在其内部存储执行逻辑运算、顺序控制、定时、计数和算术运算等操作的指令,并通过数字式或模拟式的输入和输出,控制各种类型的机械或生产过程。
3
1、操作:西门子 smart2000 ,使用工具进行通讯
VD 4byte
VW 2byte
VB 1byte
V102.0 读一1bit
VB102 读1byte
VW102 读2byte
VD102 读4byte
打开状态图表
二、Modbus
Modbus是一种通信协议,主要用于工业电子设备之间进行数据交换。
通讯的模型:
1、模拟测试(TCP)
所需软件:
mbpoll.exe
mbslave.exe
激活码:
注册码 对 7和 6 都可以使用
poll 注册码
5A5742575C5D10
slave 注册码
5455415451475662
建立 slave,即服务端 (poll,客户端也是类似的)
进行连接 :
设置连接信息
收发信息的具体情况:
1-2、模拟测试(串口)
所需软件:
创建虚拟串口对:
建立 主站 poll
建立从站 slave
2、存储区、存储区代码、范围
注:在这里布尔和线圈是一个意思:即一位的数据
注:一个区的空间为: 65536 每个为 2byte 大(short)
3、关于读写的功能码
4、协议分类
注:ModbusASCII因为速度慢,很少被使用
ModbusRTU、ModbusASCII 一般用串口
ModbusTCP 一般用以太网
5、ModbusRTU协议:
举个例子:
6、ModbusTCP
注:Tx的最后4个字节:00 00 00 02,00 00 表示起始 , 而 00 02 表示读两个字节
三、串口
简介:
一位一位的发送数据(以协上好的频率(波特率)和格式)
格式:
9针 串口:
分类:
RS-232
短距离通信
RS-422
长距离通信
RS-485
折中,
通常在半双工的模式下工作
RS-485标准理论上支持长达1200米的传输距离
单工: 类似,广播
半双工: 类似,对讲机
全双工: 类似,电话
测试:虚拟串口
二、C# 通信库的使用
1、s7通信库
1、举例:写一个C#与s7的通信
(1)、所需软件:
S7-PLCSIM Advanced V.30
TIA Portal V17
VD 4byte
VW 2byte
VB 1byte
(2)、界面:
(3)、添加所需库:
S7netplus
thinger.DataConvertLib
(4)、代码:
<1>.简单 测试下 连接-读写- using S7.Net;
- 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 WindowsFormsApp1
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- Test();
- }
- Plc plc = null;
- private void Test()
- {
- plc = new Plc(CpuType.S7200Smart, "192.168.2.1", 0, 0);
- plc.Open();
- //读取数据
- object data = plc.Read("M20.0");
- this.label1.Text = data.ToString();
- //写入数据
- plc.Write("M20.0", false);
- //不支持V区直接操作,需要映射成DB1
- plc.Write("DB1.DBX2000.0", true);
- plc.Close();
- }
- }
- }
复制代码<2>.简单 的封装下- using S7.Net;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace WindowsFormsApp1
- {
- public class S7NetLib
- {
- private Plc s7netlib = null; //字段
- //属性
- public CpuType CPUType { get;set; }
- public string IPAddress { get; set; }
- public short Rack { get; set; }
- public short Slot { get; set; }
- //构造函数,初始化连接 所需的变量
- public S7NetLib(CpuType cpuType,string ip,short rack,short slot)
- {
- this.CPUType = cpuType;
- this.IPAddress = ip;
- this.Rack = rack;
- this.Slot = slot;
- }
- /// <summary>
- /// 打开PLC连接
- /// </summary>
- public void OpenPLC()
- {
- if(this.s7netlib == null)
- {
- s7netlib = new Plc(CPUType,IPAddress,Rack,Slot);
- }
- if (!this.s7netlib.IsConnected)
- {
- s7netlib.ReadTimeout = 1000;//设置超时时间
- s7netlib.WriteTimeout = 1000;
- s7netlib.Open();//建立连接
- }
- }
- /// <summary>
- /// 关闭PLC连接
- /// </summary>
- public void ClosePLC()
- {
- if(null != this.s7netlib && this.s7netlib.IsConnected)
- {
- this.s7netlib.Close();
- }
- }
- /// <summary>
- /// 给plc单个变量写入数据
- /// </summary>
- /// <param name="varAddress">写到那里去</param>
- /// <param name="varValue">写入的值</param>
- public void WriteDataToPLC(string varAddress, object varValue)
- {
- OpenPLC();
- lock (this)
- {
- this.s7netlib.Write(varAddress, varValue);
- }
- }
- /// <summary>
- /// 读取一段数据
- /// </summary>
- /// <param name="dataType">存储区类型</param>
- /// <param name="db">DB号</param>
- /// <param name="startByteAdr">开始字节地址</param>
- /// <param name="count">字节数量</param>
- /// <returns>字节数组</returns>
- public byte[] ReadDataFromPLC(DataType dataType,int db,int startByteAdr,int count)
- {
- lock (this)
- {
- byte[] bytes = this.s7netlib.ReadBytes(dataType,db,startByteAdr,count);
- return bytes;
- }
- }
- }
- }
复制代码- using S7.Net;
- using System.Windows.Forms;
- namespace WindowsFormsApp1
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- Test();
- }
- private void Test()
- {
- S7NetLib plc = new S7NetLib(CpuType.S7200, "192.168.2.1", 0, 0);
- plc.WriteDataToPLC("M2.2", true);
- byte[] dataBytes = null;
- dataBytes = plc.ReadDataFromPLC(DataType.DataBlock, 1, 0, 10);
- }
- }
- }
复制代码一次读一个PDU 的长度,不同 CPU的 PDU 的长度不同
2、C# + SQLSERVER
〇、环境
软件的安装(服务器端、客户端)
服务器端:
SQL Sever 下载地址:
https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads
客户端
服务器端的操作:
客户端的操作:
两种连接方式:
SQL Server 的连接配置(增加使用密码登录的用户):
第一步:
第二步:
第三步: 重新启动,在连接登录
.
开启远程用户登录的方式(使用 IP 和 端口号)
第一步:
第二步:
第三步:重启服务
右键我的电脑,点击属性
第四步:最后登录
一、操作软件:- SQL Server Management Studio
复制代码
1、两种连接方式:
2、新建表
然后 ctrl+s 保存
3、添加数据
4、查询数据
注:注释是在前面加 –
5、解决不允许保存的弹窗
6、设置主键
7、更改数据(增加、删除、需改)- --查
- select * from UserT
- --存
- --新增
- insert into UserT(UserName,Password,NickName) values('111','222','333')
- --删除
- delete from UserT where UserName='111'
- delete from UserT where UserName='111' and Password='888'
- --修改
- update UserT set UserName='a' where UserName='111'
复制代码到某个指定的数据库 - use QingTongXiaWaterPlant_test
- go
复制代码修改某一段名的数据类型: - use QingTongXiaWaterPlant_test
- go
- alter table dbo.WaterFlowData alter column d17 float null;
复制代码二、数据库数据类型
三、数据库的约束
四、运算符:
五、SQL 语句
(1)、搜索当前存在哪些数据库:- select * from sysdatabases
复制代码(2)、创建数据库:
1、创建数据库所在的文件夹
建好的文件
2、执行 sql语句 - use master
- go
- if exists(select * from sysdatabases where name='MISDB') --如果原来存在这个数据库,则进行删除
- drop database MISDB
- go
- --创建数据库
- create database MISDB
- on primary
- (
- name='MISDB_MData',--必须唯一
- filename='D:\DB\MISDB_MData.mdf', --物理文件名,主存储文件
- size=30MB,filegrowth=10MB
- )
- ,
- (
- name='MISDB_nData',
- filename='D:\DB\DBMISDB_nData.ndf', --次存储文件
- size=20MB,
- filegrowth=10MB
- )
- log on
- (
- name='MISDB_log1',
- filename='D:\DB\MISDB_log1.ldf', --日志文件
- size=20MB,
- filegrowth=10MB
- )
- ,
- (
- name='MISDB_log2',
- filename='D:\DB\MISDB_log2.ldf', --日志文件
- size=20MB,
- filegrowth=10MB
- )
复制代码(3)、创建表:- --创建数据表,是在指定的数据库里面
- use MISDB
- go
- if exists(select * from sysobjects where name='Department') --如果已经有了 Department 表则对其进行删除
- drop table Department
- go
- create table Department
- (
- DepartmentId int identity(10,1)primary key,--部门字段值,由系统自动生成,从10开始,每次增加1 primary key 是主键的标识
- DepartmentName varchar(50)not null
- )
- go
- if exists(select * from sysobjects where name='Post') --如果已经有了 Post 表则对其进行删除
- drop table Post
- go
- create table Post
- (
- PostId int identity(10,1)primary key,
- PostName varchar(50) not null
- )
- go
- if exists(select * from sysobjects where name='Employee')
- drop table Employee
- go
- create table Employee
- (
- EmplyeeId int identity(100,1) primary key,
- EmplyeeName varchar(50) not null,
- Gender char(2) not null check(Gender='男' or Gender='女'),
- NowAddress nvarchar(100) default('地址不详'),
- IdNo char(18) not null check(len(Idno)=18),--检查约束
- WeiXinNumber varchar(20)not null,
- PhoneNumber varchar(50) not null,
- OtherWork nvarchar(50) not null,
- EntryDate datetime not null,
- PostId int references Post(PostId), --外键引用
- DepartmentId int references Department(DepartmentId) --外键引用
- )
- go
复制代码(4)、简单的 增、删、改、查- --查
- select * from UserT
- --存
- --新增
- insert into UserT(UserName,Password,NickName) values('111','222','333')
- --删除
- delete from UserT where UserName='111'
- delete from UserT where UserName='111' and Password='888'
- --修改
- update UserT set UserName='a' where UserName='111'
复制代码到某个指定的数据库 - use QingTongXiaWaterPlant_test
- go
复制代码修改某一段名的数据类型: - use QingTongXiaWaterPlant_test
- go
- alter table dbo.WaterFlowData alter column d17 float null;
复制代码(5)、增加- use MISDB
- go
- select * from Department
- select * from Post
- select * from Employee
- insert into Department(DepartmentName)
- values('开发部'),('测试部'),('财务部'),('人事部')
- inSert into Post(PostName)
- values('软件工程师'),('测试工程师'),('实施工程师'),('财务经理'),('人事经理')
- insert into Employee(EmployeeName,Gender,NowAddress,IdNo,
- WeiXinNumber,PhoneNumber,OtherWork,EntryDate,PostId,DepartmentId)values
- ('Kiter10','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter11','男','北京','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter12','男','福州','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter13','男','西安','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter14','男','苏州','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter15','男','咸阳','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter16','男','永寿','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter17','女','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter18','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter19','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter20','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter21','女','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter22','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter23','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter24','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter25','女','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter26','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
- ('Kiter27','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12)
复制代码(6)、删除- delete from Employee where EmployId=112
- delete from Employee where EmployId>=117
复制代码(7)、修改- update Employee set EmployeeName='小王',NowAddress='天津X'where EmployId=101
复制代码(8)、查询(及内查询)- select * from Department
- select * from Post
- select * from employee
- --条件查询
- select EmployId,EmployeeName,Gender,NowAddress,PhoneNumber
- from Employee where EmployId>=105 and EmployId<=115 and gender='女'
- update Employee set EmployeeName='小王',NowAddress='天津X'where EmployId=101
- delete from Employee where EmployId=112
- delete from Employee where EmployId>=117
- --内连接查询
- select EmployId,EmployeeName,PhoneNumber,Post.PostId,Post.PostName
- from Employee
- inner join Post on Post.PostId=Employee.PostId
- --内连接查询
- select EmployId,EmployeeName,PhoneNumber,
- Post.PostId,PostName,DepartmentName
- from Employee
- inner join Post on Post.PostId=Employee.PostId
- inner join Department on Department.DepartmentId=Employee.DepartmentId
- --聚合查询
- select count(*) as 员工总数 from Employee
- select 编号平均数=avg(EmployId)from Employee
- select 编号最小值=min(EmployId)from Employee
- select 编号最大值=max(EmployId)from Employee
复制代码(9)、给表增加列:- ALTER TABLE Employees
- ADD
- Column1 INT,
- Column2 NVARCHAR(50),
- Column3 DATETIME;
复制代码(10)、存储过程:
新建 - CREATE PROCEDURE JiaYao
- -- 输入参数 执行哪个加药
- @Index varchar(32) ='',
- @C1_DangLiang real=0,
- -- 输出
- @dosage real output
- AS
- BEGIN
- -- 为了不返回 每条sql 影响多少条记录的信息
- SET NOCOUNT ON
-
- select
- avg(data_js_d1) as js_cod,
- from RealData
-
- if @Index='PAC1'
- begin
- set @dosage =js_cod/3;
- end
- if @Index='PAC2'
- begin
- set @dosage =js_cod/2;
- end
- END
复制代码修改 - ALTER PROCEDURE JiaYao
- -- 输入参数 执行哪个加药
- @Index varchar(32) ='',
- @C1_DangLiang real=0,
- -- 输出
- @dosage real output
- AS
- BEGIN
- -- 为了不返回 每条sql 影响多少条记录的信息
- SET NOCOUNT ON
-
- select
- avg(data_js_d1) as js_cod,
- from RealData
-
- if @Index='PAC1'
- begin
- set @dosage =js_cod/3;
- end
- if @Index='PAC2'
- begin
- set @dosage =js_cod/2;
- end
- END
复制代码执行的sql - DECLARE @dosage real;
- EXEC JiaYao @dosage=1.3,
- -- 输入参数 执行哪个加药
- @Index ='PAC1',
复制代码六、在C#中 使用,SQLServer 数据库
- using System;
- using System.Collections.Generic;
- using System.Data.SqlClient;
- using System.Data;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Diagnostics;
- using System.Management.Instrumentation;
- namespace ConsoleApp1
- {
- public class SqlServer
- {
- /** 建立连接所需要的信息
- * Server 是服务器的地址
- * DataBase 是数据库的名称
- * Uid 是登录的用户名
- * Pwd 是用户名的密码
- */
- //private string connString1 = "Server=E2JMKGABJ62SR4X\\SQLEXPRESS;DataBase=MISDB;Uid=sa;Pwd=123456";
- //private string connString1 = "Server=192.168.31.130,1433\\SQLEXPRESS;DataBase=MISDB;Uid=sa;Pwd=123456";
- private string connString1 = "Server=192.168.31.130,1433;DataBase=MISDB;Uid=sa;Pwd=123456";
- //建立连接的方法
- public void ConnectDB()
- {
- SqlConnection conn = new SqlConnection(connString1);
- conn.Open();
- if (conn.State == System.Data.ConnectionState.Open)
- {
- Console.WriteLine("连接成功");
- }
- conn.Close();
- if (ConnectionState.Closed == conn.State)
- {
- Console.WriteLine("连接关闭");
- }
- }
- //插入语句的写法
- public void Insert()
- {
- //创建建立连接的对象 -- SqlConnection
- SqlConnection conn = new SqlConnection(connString1);
- //sql语句,
- string sql = "insert into Employee(EmployeeName,Gender,NowAddress,IdNo,WeiXinNumber,PhoneNumber,OtherWork,EntryDate,PostId,DepartmentId)Values('Kiter30','女','天津','123456789123456789','uio001','96587112365','没有的','2024-10-06',10,12)";
- //创建执行 sql 语句的对象
- SqlCommand cmd = new SqlCommand(sql, conn);
- //连接
- conn.Open();
- //执行sql语句
- int result = cmd.ExecuteNonQuery();
- //断开连接
- conn.Close();
- Console.WriteLine("受影响的行数:"+result);
- }
- //变更数据的写法
- public void Update()
- {
- //创建建立连接的对象 -- SqlConnection
- SqlConnection conn = new SqlConnection(connString1);
- //sql语句
- string sql = "update Employee set EmployeeName='UBM'where EmployId=121";
- //创建执行 sql 语句的对象
- SqlCommand cmd = new SqlCommand(sql, conn);
- //连接
- conn.Open();
- //执行sql语句
- int result = cmd.ExecuteNonQuery();
- //断开连接
- conn.Close();
-
- Console.WriteLine("受影响的行数:" + result);
- }
- //删除表中的记录
- public void Delete()
- {
- //创建建立连接的对象 -- SqlConnection
- SqlConnection conn = new SqlConnection(connString1);
- //要执行的 sql 语句
- string sql = "delete from Employee where EmployId=102";
- //实例化 要执行 sql的对象 -- SqlCommand
- SqlCommand cmd = new SqlCommand(sql, conn);
- //建立连接
- conn.Open();
- //执行 sql语句
- int result = cmd.ExecuteNonQuery();
- //关闭练级
- conn.Close();
-
- Console.WriteLine("受影响的行数:" + result);
- }
- //执行查询结果为1个的 sql 语句
- public void GetSingleResult()
- {
- //创建建立连接的对象 -- SqlConnection
- SqlConnection conn = new SqlConnection(connString1);
- //要执行的 sql 语句
- string sql = "select EmployeeName from Employee where EmployId=101";
- //实例化 要执行 sql的对象 -- SqlCommand
- SqlCommand cmd = new SqlCommand(sql, conn);
- //建立连接
- conn.Open();
- //执行 sql语句 ExecuteScalar 是执行只有一个返回结果的sql 语句
- object result = cmd.ExecuteScalar();
- //关闭连接
- conn.Close();
-
- Console.WriteLine(result);
- }
- //执行查询结果为1个的 sql 语句
- public void GetSingleResult2()
- {
- //创建建立连接的对象 -- SqlConnection
- SqlConnection conn = new SqlConnection(connString1);
- //要执行的 sql 语句
- string sql = "select 员工总数=count(*)from Employee";
- //实例化 要执行 sql的对象 -- SqlCommand
- SqlCommand cmd = new SqlCommand(sql, conn);
- //建立连接
- conn.Open();
- //执行 sql语句 ExecuteScalar 是执行只有一个返回结果的sql 语句
- object result = cmd.ExecuteScalar();
- int count = (int)result;//如果程序需要使用具体数据类型,就可以转换
- //关闭连接
- conn.Close();
- Console.WriteLine(count);
- }
- //用 ExecuteScalar 来执行 插入操作,返回看新增的记录是第几条的
- public void GetSingleResult3()
- {
- SqlConnection conn = new SqlConnection(connString1);
- string sql = "insert into Employee(EmployeeName,Gender," +
- "NowAddress,IdNo,WeiXinNumber,PhoneNumber,OtherWork," +
- "EntryDate,PostId,DepartmentId)"+
- "Values('Kiter50','男','北京','123456789123456789','qwer1','96325451784','没有','2024-11-07',10,12)";
- sql += ";select @@Identity";
- SqlCommand cmd = new SqlCommand (sql,conn);
- conn.Open();
- int result = Convert.ToInt32(cmd.ExecuteScalar());
- conn.Close();
- Console.WriteLine("编号:"+result);
- }
- //读取多条记录 (查询的 多个表)
- public void GetReaderList()
- {
- //创建建立连接的对象 -- SqlConnection
- SqlConnection conn = new SqlConnection(connString1);
- //要执行的 sql 语句
- string sql = "select EmployeeName,Gender,NowAddress from Employee";
- //实例化 要执行 sql的对象 -- SqlCommand
- SqlCommand cmd = new SqlCommand(sql, conn);
- //建立连接
- conn.Open();
- //执行结果集查询
- SqlDataReader reader = cmd.ExecuteReader();
- //逐行读取
- while (reader.Read())
- {
- string result = reader["EmployeeName"].ToString() + reader["Gender"] + reader["NowAddress"];
- Console.WriteLine(result);
- }
- //释放资源
- reader.Close(); //关闭读取器
- conn.Close(); //关闭连接
- }
- //读取多条记录(查询的是多个表)
- public void GetReaderList2()
- {
- //创建建立连接的对象 -- SqlConnection
- SqlConnection conn = new SqlConnection(connString1);
- //要执行的 sql 语句
- string sql = "select EmployeeName,Gender,NowAddress from Employee";
- sql += ";select DepartmentId,DepartmentName from Department";
- //实例化 要执行 sql的对象 -- SqlCommand
- SqlCommand cmd = new SqlCommand(sql, conn);
- //建立连接
- conn.Open();
- //执行结果集查询
- SqlDataReader reader = cmd.ExecuteReader();
- //逐行读取
- while (reader.Read())
- {
- string result = reader["EmployeeName"].ToString()+"\t"+reader[1]+"\t"+reader["NowAddress"];
- Console.WriteLine(result);
- }
- Console.WriteLine("*************");
- if (reader.NextResult())
- {
- while (reader.Read())
- {
- Console.WriteLine($"{reader["DepartmentId"]}\t{reader["DepartmentName"]}");
- }
- }
- //关闭读取器
- reader.Close();
- //关闭连接
- conn.Close();
- }
- //使用 DataSet 和 SqlDataAdapter 读取多条记录
- public void GetDataSet1()
- {
- //创建连接对象
- SqlConnection conn = new SqlConnection(connString1);
- //sql 语句
- string sql = "select EmployeeName,Gender,NowAddress from Employee";
- //创建执行sql的对象
- SqlCommand cmd = new SqlCommand(sql, conn);
- //打开连接
- conn.Open();
- //创建数据适配器对象
- SqlDataAdapter da = new SqlDataAdapter(cmd);
- //创建一个数据集对象
- DataSet ds = new DataSet();
- //将查询到到结果填入到,内存中(DataSet)
- da.Fill(ds);
- //关闭连接
- conn.Close();
- //读取数据
- DataTable dt = ds.Tables[0];
- foreach(DataRow dr in dt.Rows)
- {
- Console.WriteLine($"{dr["EmployeeName"]}\t{dr["Gender"]}\t{dr["NowAddress"]}");
- }
- }
- //使用 DataSet 和 SqlDataAdapter 读取多条记录(查询的是多个表)
- public void GetDataSet2()
- {
- //创建连接对象
- SqlConnection conn = new SqlConnection(connString1);
- //sql 语句
- string sql = "select EmployeeName,Gender,NowAddress from Employee";
- //创建执行sql的对象
- SqlCommand cmd = new SqlCommand(sql, conn);
- //打开连接
- conn.Open();
- //创建数据适配器对象
- SqlDataAdapter da = new SqlDataAdapter(cmd);
- //创建一个数据集对象
- DataSet ds = new DataSet();
- //填充数据
- da.Fill(ds,"Employee");
- cmd.CommandText = "select DepartmentId,DepartmentName from Department";
- da.Fill(ds, "Department");
- //关闭连接
- conn.Close();
- //读取数据
- DataTable dt = ds.Tables["Employee"];
- foreach(DataRow dr in dt.Rows)
- {
- Console.WriteLine($"{dr["EmployeeName"]}\t{dr["Gender"]}\t{dr["NowAddress"]}");
- }
- Console.WriteLine("........................");
- foreach(DataRow dr in ds.Tables["Department"].Rows)
- {
- Console.WriteLine($"{dr["DepartmentId"]}\t{dr["DepartmentName"]}");
- }
- }
- //写带 参数的SQL 语句
- public void GetReaderList5()
- {
- //创建建立连接的对象 -- SqlConnection
- SqlConnection conn = new SqlConnection(connString1);
- //要执行的 sql 语句
- string sql = "select EmployeeName,Gender,NowAddress from Employee where EmployId > @Number";
- SqlParameter[] param = new SqlParameter[]
- {
- new SqlParameter("@Number",106)
- };
- //实例化 要执行 sql的对象 -- SqlCommand
- SqlCommand cmd = new SqlCommand(sql, conn);
- //添加参数
- cmd.Parameters.AddRange(param);
- //建立连接
- conn.Open();
- //执行结果集查询
- SqlDataReader reader = cmd.ExecuteReader();
- //逐行读取
- while (reader.Read())
- {
- string result = reader["EmployeeName"].ToString() + "\t" + reader[1] + "\t" + reader["NowAddress"];
- Console.WriteLine(result);
- }
- //关闭读取器
- reader.Close();
- //关闭连接
- conn.Close();
- }
- }
- }
复制代码- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace ConsoleApp1
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- SqlServer sqlServer = new SqlServer();
- //建立连接,然后断开
- //sqlServer.ConnectDB();
- //插入新的行
- //sqlServer.Insert();
- //修改数据库中的信息
- //sqlServer.Update();
- //删除数据库中的记录
- //sqlServer.Delete();
- //执行只返回一个结果的 sql 语句
- //sqlServer.GetSingleResult();
- //执行只返回一个结果的 sql 语句
- //sqlServer.GetSingleResult2();
- //用 ExecuteScalar 来执行 插入操作,返回看新增的记录是第几条的
- //sqlServer.GetSingleResult3();
- //读取多条记录
- //sqlServer.GetReaderList();
- //读取多个表的多条记录
- //sqlServer.GetReaderList2();
- //使用 SqlDataAdapter 和 DataSet 读取数据
- //sqlServer.GetDataSet1();
- //使用 SqlDataAdapter 和 DataSet 读取多个表的数据
- //sqlServer.GetDataSet2();
- //使用带参的sql语句
- sqlServer.GetReaderList5();
- Console.ReadLine();
- }
- }
- }
复制代码查询
通过关闭 SqlDataReader,来关闭 SqlConnection
七、SqlHelper
先安装库:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Configuration;
- using System.Web;
- //using System.Data.SqlClient;
- using System.Data;
- using Microsoft.SqlServer.Server;
- using Microsoft.Data.SqlClient;
- using System.Configuration;
- namespace ToolsLib
- {
- public class SqlServerHelper
- {
- //用于连接数据库的字符串
- //private static string ConnString { get; set; } = ConfigurationManager.ConnectionStrings["connString1"].ToString();
- private static string ConnString { get; set; } = ConfigurationManager.AppSettings["connString1"];
- /// <summary>
- /// 执行 insert\update\delete 类型的 sql 语句
- /// </summary>
- /// <param name="cmdText">sql语句或存储过程名称</param>
- /// <param name="paramArray">参数数组</param>
- /// <returns>受影响的行数</returns>
- /// <exception cref="Exception"></exception>
- public static int ExecuteNonQuery(string cmdText, SqlParameter[] paramArray = null)
- {
- SqlConnection conn = new SqlConnection(ConnString);
- SqlCommand cmd = new SqlCommand(cmdText, conn);
- if (paramArray != null)
- {
- cmd.Parameters.AddRange(paramArray);
- }
- try
- {
- conn.Open();
- return cmd.ExecuteNonQuery();//执行
- }
- catch (Exception ex)
- {
- //可以在这个地方写入日志(log文件)
- string errorMsg = $"{DateTime.Now}:执行public static int ExecuteNonQuery(sting cmdText,SqlParameter[]para---{ex.Message}";
- throw new Exception(errorMsg);
- }
- finally
- {
- conn.Close();
- }
- }
- /// <summary>
- /// 执行查询语句,查询结果是但是一个结果
- /// </summary>
- /// <param name="cmdText"></param>
- /// <param name="paramArray"></param>
- /// <returns></returns>
- /// <exception cref="Exception"></exception>
- public static object ExecuteScalar(string cmdText, SqlParameter[] paramArray = null)
- {
- SqlConnection conn = new SqlConnection(ConnString);
- SqlCommand cmd = new SqlCommand(cmdText, conn);
- if (paramArray != null)
- {
- cmd.Parameters.AddRange(paramArray);
- }
- try
- {
- conn.Open();
- return cmd.ExecuteScalar();
- }
- catch (Exception ex)
- {
- throw new Exception("执行public staticobjectExecute Scalar(string cmdText,SqlParameter[] paramArray = null)异常" + ex.Message);
- }
- finally
- {
- conn.Close();//关闭连接
- }
- }
- /// <summary>
- /// 执行查询语句
- /// </summary>
- /// <param name="cmdText"></param>
- /// <param name="paramArray"></param>
- /// <returns></returns>
- /// <exception cref="Exception"></exception>
- public static SqlDataReader ExecuteReader(string cmdText, SqlParameter[] paramArray = null)
- {
- SqlConnection conn = new SqlConnection(ConnString);
- SqlCommand cmd = new SqlCommand(cmdText, conn);
- if (paramArray != null)
- {
- cmd.Parameters.AddRange(paramArray);
- }
- try
- {
- conn.Open();
- //这里返回的 SqlDataReader 是用来进行进一步查询的,
- //这里的 加的入参是:CommandBehavior.CloseConnection 为了,关闭 SqlDataReader后来自动关闭 conn连接 做设置
- //因为 SqlDataReader 是需要在外部进行访问的
- return cmd.ExecuteReader(CommandBehavior.CloseConnection);//执行
- }
- catch (Exception ex)
- {
- throw new Exception($"执行public staticobjectExecute Scalar(stringcmdText,SqlParameter[] paramArray=null) ---{ex.Message}");
- }
- }
- /// <summary>
- /// 返回包含一张数据表的数据集的查询
- /// </summary>
- /// <param name="sql"></param>
- /// <param name="tableName"></param>
- /// <returns></returns>
- /// <exception cref="Exception"></exception>
- public static DataSet GetDataSet(string sql, string tableName = null)
- {
- SqlConnection conn = new SqlConnection(ConnString);
- SqlCommand cmd = new SqlCommand(sql, conn);
- SqlDataAdapter da = new SqlDataAdapter(cmd);
- DataSet ds = new DataSet();
- try
- {
- conn.Open();
- if (tableName == null)
- {
- da.Fill(ds);
- }
- else
- {
- da.Fill(ds, tableName);
- }
- return ds;
- }
- catch (Exception ex)
- {
- throw new Exception($"执行public static DataSet GetDataSet(string sql,string tableName=null)方法出现异常{ex.Message}");
- }
- finally
- {
- conn.Close();
- }
- }
- public static DataSet GetDataSet(Dictionary<string, string> dicTableAndSql)
- {
- SqlConnection conn = new SqlConnection(ConnString);
- SqlCommand cmd = new SqlCommand();
- cmd.Connection = conn;
- SqlDataAdapter da = new SqlDataAdapter(cmd);
- DataSet ds = new DataSet();
- try
- {
- conn.Open();
- foreach (string tbName in dicTableAndSql.Keys)
- {
- cmd.CommandText = dicTableAndSql[tbName];
- da.Fill(ds, tbName);//加入多个表
- }
- return ds;
- }
- catch (Exception ex)
- {
- throw new Exception("执行public static DataSet GetDataSet(string ssql,string tableName=null)方法出行异常" + ex.Message);
- }
- finally
- {
- conn.Close();
- }
- }
- }
- }
复制代码八、存储过程的写法:
创建 - SET ANSI_NULLS ON
- GO
- SET QUOTED_IDENTIFIER ON
- GO
- CREATE PROCEDURE TestProcedure
- @Parameter1 Int =0,
- @Parameter2 Int output
- AS
- BEGIN
- SET NOCOUNT ON
- select * from UserT;
- Set @Parameter2 = 999;
- END
- GO
复制代码修改 - USE [MyDB]
- GO
- /****** Object: StoredProcedure [dbo].[TestProcedure] Script Date: 12/17/2024 10:08:29 AM ******/
- -- 与null比较的结果会被视为 未知,而不是 true 或 false
- SET ANSI_NULLS ON
- GO
- -- 可以使用用双引号,引起来的关键字
- SET QUOTED_IDENTIFIER ON
- GO
- ALTER PROCEDURE [dbo].[TestProcedure]
- -- 输入参数
- @Parameter1 Int =0,
- -- 输出参数
- @Parameter2 Int output
- AS
- BEGIN
- -- 为了不返回 每条sql 影响多少条记录的信息
- SET NOCOUNT ON
- select * from UserT;
- Set @Parameter2 = 999;
- END
复制代码执行 - declare @Parameter2 int;
- exec TestProcedure @Parameter1=20, @Parameter2= @Parameter2 output;
- select @Parameter2 as Parameter2;
复制代码3、NModbus4 通讯库的使用
1、使用串口,封装 NModbus4 库
安装 NModbus4 库:
封装的代码: - using Modbus.Device;
- using System;
- using System.Collections.Generic;
- using System.IO.Ports;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace WindowsFormsApp1
- {
- /// <summary>
- /// 基于NModbus4的开源库的二次封装
- /// </summary>
- internal class ModbusRTU
- {
- #region 串口打开
- //声明.NET串口对象
- private SerialPort serialPort;
- //声明Modbus协议串口主设备对象
- private ModbusSerialMaster master;
- // COM1 9600 N 8 1
- public bool Connect(string portName, int baudRate,Parity parity,int dataBits,StopBits stopBits)
- {
- if(this.serialPort == null && this.serialPort.IsOpen)
- {
- this.serialPort.Close();
- }
- try
- {
- //创建.NET串口对象
- this.serialPort = new SerialPort(portName,baudRate, parity,dataBits,stopBits);
- //设置串口的读写超时时间(防止长时间阻塞)
- this.serialPort.ReadTimeout = 1000;
- this.serialPort.WriteTimeout = 1000;
- //打开 .NET 串口
- this.serialPort.Open();
- //使用 Modbus串口工厂方法 创建 Modbus串口主设备 对象
- master = ModbusSerialMaster.CreateRtu(this.serialPort);
- return true;
- }
- catch(Exception ex)
- {
- //打印异常信息
- throw new Exception("[串口]打开失败,"+ex.Message);
- }
- }
- #endregion
- #region 关闭串口
- public void DisConnect()
- {
- if(this.serialPort != null && this.serialPort.IsOpen)
- {
- //this.serialPort?.Close();
- this.serialPort.Close();
- }
- master = null;
- }
- #endregion
- #region 读取数据
- /// <summary>
- /// 【01】功能码:读取输出线圈
- /// </summary>
- /// <param name="slaveId">从站地址</param>
- /// <param name="start">起始线圈地址</param>
- /// <param name="length">线圈的数量</param>
- /// <returns>返回bool数组</returns>
- /// <exception cref="Exception"></exception>
- public bool[]ReadOutputCoils(byte slaveId,ushort start,ushort length)
- {
- try
- {
- //Coils 线圈的意思
- return this.master.ReadCoils(slaveId, start, length);
- }
- catch(Exception ex)
- {
- throw new Exception("[读取输出线程]失败" + ex.Message);
- }
- }
- /// <summary>
- /// [02] 功能码:读取输入线圈
- /// </summary>
- /// <param name="slaveId">从站地址</param>
- /// <param name="start">起始线圈地址</param>
- /// <param name="length">线圈的数量</param>
- /// <returns>返回bool数组</returns>
- /// <exception cref="Exception"></exception>
- public bool[] ReadInputCoils(byte slaveId, ushort start, ushort length)
- {
- try
- {
- return this.master.ReadInputs(slaveId, start, length);
- }
- catch (Exception ex)
- {
- throw new Exception("[读取输入线圈]失败:" + ex.Message);
- }
- }
- // 一个寄存器是两个 字节的大小
- /// <summary>
- /// 【03】 功能码:读取输出寄存器
- /// </summary>
- /// <param name="slaveId">从站地址</param>
- /// <param name="start">起始寄存器地址</param>
- /// <param name="length">寄存器的数量</param>
- /// <returns>返回byte数组</returns>
- /// <exception cref="Exception"></exception>
- public byte[] ReadHoldingRegister(byte slaveId,ushort start,ushort length)
- {
- try
- {
- //获取数据数组
- ushort[] data = this.master.ReadHoldingRegisters(slaveId, start, length);
- // 一个寄存器是两个 字节的大小
- //把ushort类型数组,转换成List字节数组
- List<byte> result = new List<byte>();
- foreach(var item in data)
- {
- result.AddRange(BitConverter.GetBytes(item));
- }
- return result.ToArray();
- }
- catch(Exception ex)
- {
- throw new Exception("[读取输出寄存器]失败," + ex.Message);
- }
- }
- /// <summary>
- /// [04] 功能码:读取输入寄存器
- /// </summary>
- /// <param name="slaveId">从站地址</param>
- /// <param name="start">起始寄存器地址</param>
- /// <param name="length">寄存器的数量</param>
- /// <returns>返回byte数组</returns>
- /// <exception cref="Exception"></exception>
- public byte[] ReadInputRegister(byte slaveId,ushort start,ushort length)
- {
- try
- {
- //获取数据数组
- ushort[] data = this.master.ReadInputRegisters(slaveId, start, length);
- //把ushort类型的数组,转换成List字节数组
- List<byte> result = new List<byte>();
- foreach (var item in data)
- {
- result.AddRange(BitConverter.GetBytes(item));
- }
- return result.ToArray();
- }
- catch(Exception ex)
- {
- throw new Exception("[读取输入寄存器]失败" + ex.Message);
- }
- }
-
- #endregion
- #region 写入数据
- /// <summary>
- /// [05] 功能码:预置单线圈
- /// </summary>
- /// <param name="slaveId">从站地址</param>
- /// <param name="start">当前线圈地址</param>
- /// <param name="value">线圈的值</param>
- /// <returns></returns>
- /// <exception cref="Exception"></exception>
- public bool PreSetSingleCoil(byte slaveId,ushort start,bool value)
- {
- try
- {
- this.master.WriteSingleCoil(slaveId, start, value);
- return true;
- }
- catch(Exception ex)
- {
- throw new Exception("[预置单线圈]失败," + ex.Message);
- }
- }
- /// <summary>
- /// [06]功能码:预置单寄存器
- /// </summary>
- /// <param name="slaveId">从站地址</param>
- /// <param name="address">寄存器地址</param>
- /// <param name="value">字节地址(2个字节)</param>
- /// <returns></returns>
- /// <exception cref="Exception"></exception>
- public bool PreSetSingleRegister(byte slaveId,ushort address,byte[] value)
- {
- try
- {
- this.master.WriteSingleRegister(slaveId, address, BitConverter.ToUInt16(value, 0));
- return true;
- }
- catch (Exception ex)
- {
- throw new Exception("【预置单寄存器】失败," + ex.Message);
- }
- }
- public bool PreSetSingleRegister(byte slaveId,ushort address,short value)
- {
- return PreSetSingleRegister(slaveId, address, BitConverter.GetBytes(value));
- }
- public bool PreSetSingleRegister(byte slaveId,ushort address,ushort value)
- {
- return PreSetSingleRegister(slaveId, address, BitConverter.GetBytes(value));
- }
- /// <summary>
- /// 【0F】 功能码 预置多个线圈
- /// </summary>
- /// <param name="slaveId">从站地址</param>
- /// <param name="start">线圈开始地址</param>
- /// <param name="value">布尔数组</param>
- /// <returns></returns>
- /// <exception cref="Exception"></exception>
- public bool PreSetMutiCoils(byte slaveId,ushort start,bool[] value)
- {
- try
- {
- this.master.WriteMultipleCoils(slaveId, start, value);
- return true;
- }
- catch(Exception ex){
- throw new Exception("[预制多线圈]失败," + ex.Message);
- }
- }
- /// <summary>
- /// [10] 功能码:预制多个寄存器
- /// </summary>
- /// <param name="slaveId">从站地址</param>
- /// <param name="start">寄存器开始地址</param>
- /// <param name="values">字节数组</param>
- /// <returns></returns>
- /// <exception cref="Exception"></exception>
- public bool PreSetMultiRegister(byte slaveId,ushort start, byte[] values)
- {
- //必须是偶数字节
- // 因为两字节 , 才是也给寄存器的大小
- if(values == null||values.Length == 0 || values.Length%2 == 1)
- {
- return false;
- }
- //将字节数组转换成ushort数组
- ushort[] data = new ushort[values.Length / 2];
- for (int i = 0; i < values.Length; i += 2)
- {
- data[i] = BitConverter.ToUInt16(values, i);
- }
- try
- {
- this.master.WriteMultipleRegisters(slaveId, start, data);
- return true;
- }
- catch(Exception ex)
- {
- throw new Exception("[预制多寄存器]失败,"+ex.Message);
- }
- }
- /// <summary>
- /// [0F] 功能码:预制多个线圈
- /// </summary>
- /// <param name="slaveId">站地址</param>
- /// <param name="start">线圈开始地址</param>
- /// <param name="value">布尔数组</param>
- /// <returns></returns>
- /// <exception cref="Exception"></exception>
- public bool PreSetMultiCoils(byte slaveId,ushort start,bool[] value)
- {
- try
- {
- this.master.WriteMultipleCoils(slaveId,start,value);
- return true;
- }
- catch (Exception ex)
- {
- throw new Exception("[预制多个线圈]失败" + ex.Message);
- }
- }
- #endregion
- }
- }
复制代码三、手写通信库
四、WPF基本使用
0、xaml 的基础操作
xaml是一种声明型语言,一般来讲,一个标签就是一个对象;而一个标签的属性就是一个对象的属性。
给标签属性赋值有三种方式:
1、 Attribute = Value 形式
画一个 长方形 - <Rectangle Width="100" Height="80" Stroke="Black"/>
复制代码画一个三角形 - <Path Data="M 0,0 L 200,100 L 100,200 Z" Stroke="Black" Fill="Red"/>
复制代码将一个字符串转换成标签(对象)的写法:
MainWindow.xaml - <Window x:Class="WpfApp1.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:WpfApp1"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Window.Resources>
- <local:Dog x:Key="dog1" Name="Bob1"/>
- <local:Dog x:Key="dog2" Name="Bob2"/>
- <local:Dog x:Key="dog3" Name="Bob3" Child="123"/>
- </Window.Resources>
- <Grid>
- <Button Content="Hello!" Width="120" Height="30" Click="Button_Click"/>
- </Grid>
- </Window>
复制代码Dog.cs - using System.ComponentModel;
- using System.Globalization;
- namespace WpfApp1
- {
- //为类添加转换规则
- [TypeConverterAttribute(typeof(NameToDogTypeConverter))]
- public class Dog
- {
- public string Name { get; set; }
- public Dog Child { get; set; }
- }
- public class NameToDogTypeConverter : TypeConverter
- {
- //将字符串转成 Dog 的规则
- public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
- {
- string name = value.ToString();
- Dog child = new Dog();
- child.Name = name;
- return child;
- }
- }
- }
复制代码MainWindow.xaml.cs - using System.Windows;
- namespace WpfApp1
- {
- /// <summary>
- /// MainWindow.xaml 的交互逻辑
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- }
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- Dog dog =this.FindResource("dog3") as Dog; ;//找到字典资源中 标签对象的方法
- if(null != dog)
- {
- //取出标签对象中的属性
- MessageBox.Show(dog.Name + "/" + dog.Child.Name);
- }
- }
- }
- }
复制代码另一种等价的添加属性 的方式:- <Button Content="登录" FontSize="20" Height="50" Width="300"/>
复制代码- <Button Content="登录">
- <Setter Property="Background" Value="Red"/>
- <Setter Property="FontSize" Value="20"/>
- <Setter Property="Height" Value="50"/>
- <Setter Property="Width" Value="300"/>
- </Button>
复制代码2、属性标签
形如:
就是属性标签,它不是一个对象,而是对象的属性,用标签的形式来写
例子 1:
- <Window x:Class="WpfApp1.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <Rectangle Width="200" Height="160" Stroke="Blue">
- <Rectangle.Fill>
- <LinearGradientBrush>
- <LinearGradientBrush.StartPoint>
- <Point X="0" Y="0"/>
- </LinearGradientBrush.StartPoint>
- <LinearGradientBrush.EndPoint>
- <Point X="1" Y="1"/>
- </LinearGradientBrush.EndPoint>
- <LinearGradientBrush.GradientStops>
- <GradientStopCollection>
- <GradientStop Offset="0.2" Color="LightBlue"/>
- <GradientStop Offset="0.7" Color="DarkBlue"/>
- <GradientStop Offset="1.0" Color="Blue"/>
- </GradientStopCollection>
- </LinearGradientBrush.GradientStops>
- </LinearGradientBrush>
- </Rectangle.Fill>
- </Rectangle>
- </Grid>
- </Window>
复制代码例子 2:
- <Window x:Class="WpfApp1.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <Button Width="120" Height="30">
- <Button.Content>
- <Rectangle Width="20" Height="20" Stroke="DarkGreen" Fill="LawnGreen"/>
- </Button.Content>
- </Button>
- </Grid>
- </Window>
复制代码3、标签扩展
1、创建一个项目
程序入口:
默认入口点:WPF 应用程序的默认入口点是 App.xaml 和 App.xaml.cs 文件。在这些文件中定义了应用程序的启动逻辑和主窗口。
自定义入口点:如果需要,可以在代码中定义一个 Main 方法并在其中创建和运行 Application 对象,但这不是必需的,除非你有特定的初始化需求。
手写函数函数入口(一般不需要): - // Entry point defined in a custom Main method (if needed)
- public static class Program
- {
- [STAThread]
- public static void Main()
- {
- var app = new App();
- app.InitializeComponent();
- app.Run();
- }
- }
复制代码- // App.xaml.cs
- using System.Windows;
- namespace MyWpfApp
- {
- public partial class App : Application
- {
- // Application startup logic can be placed here
- protected override void OnStartup(StartupEventArgs e)
- {
- base.OnStartup(e);
- // Custom startup logic (if needed)
- }
- protected override void OnExit(ExitEventArgs e)
- {
- base.OnExit(e);
- // Custom exit logic (if needed)
- }
- }
- }
复制代码窗体 xaml 文件的解读:
2、模拟一个文本编辑的界面(使用控件:Grid | StackPanel | Button | TextBox)
准备
button的属性: Width HorizontalAlignment VerticalAlignment Height
- <Grid>
- <Button Width="200" HorizontalAlignment="Left" VerticalAlignment="Top" Height="40"/>
- <Button Width="200" HorizontalAlignment="Center" VerticalAlignment="Top" Height="40"/>
- <Button Width="200" HorizontalAlignment="Right" VerticalAlignment="Top" Height="40"/>
- <Button Width="200" HorizontalAlignment="Left" VerticalAlignment="Center" Height="40"/>
- <Button Width="200" HorizontalAlignment="Center" VerticalAlignment="Center" Height="40"/>
- <Button Width="200" HorizontalAlignment="Right" VerticalAlignment="Center" Height="40"/>
- <Button Width="200" HorizontalAlignment="Left" VerticalAlignment="Bottom" Height="40"/>
- <Button Width="200" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="40"/>
- <Button Width="200" HorizontalAlignment="Right" VerticalAlignment="Bottom" Height="40"/>
- </Grid>
复制代码Stackanel控件:
.
占用多列的写法:
Grid.ColumnSpan=“2” - <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
- <Button Height="20" Width="70"/>
- <Button Height="20" Width="70"/>
- <Button Height="20" Width="70"/>
- </StackPanel>
复制代码- <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
- <Button Height="20" Width="70"/>
- <Button Height="20" Width="70"/>
- <Button Height="20" Width="70"/>
- </StackPanel>
复制代码Grid控件:
- <Grid ShowGridLines="True">
- <Grid.RowDefinitions>
- <RowDefinition Height="1*"/>
- <RowDefinition Height="1*"/>
- <RowDefinition Height="1*"/>
- <RowDefinition Height="1*"/>
- </Grid.RowDefinitions>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- </Grid.ColumnDefinitions>
- <Button Grid.Row="1" Grid.Column="1">1,1</Button>
- <Button Grid.Row="1" Grid.Column="2">1,2</Button>
- <Button Grid.Row="1" Grid.Column="3">1,3</Button>
- <Button Grid.Row="2" Grid.Column="1">2,1</Button>
- <Button Grid.Row="2" Grid.Column="2">2,2</Button>
- <Button Grid.Row="2" Grid.Column="3">2,3</Button>
- </Grid>
复制代码Grid 的三种长度设置:
AUTO 安内容来
绝对宽高 每个单位是 1/96英寸
“1*” 按比例来
TextBox 文本编辑的控件
- <TextBox TextWrapping="Wrap"/>
复制代码应用
- <Window x:Class="WpfApp1.EditWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:WpfApp1"
- mc:Ignorable="d"
- Title="EditWindow" Height="450" Width="800">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="20"/>
- <RowDefinition Height="20"/>
- <RowDefinition Height="1*"/>
- <RowDefinition Height="20"/>
- </Grid.RowDefinitions>
- <StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal">
- <Button Height="20" Width="70" Content="文件"/>
- <Button Height="20" Width="70" Content="编辑"/>
- <Button Height="20" Width="70" Content="查看"/>
- <Button Height="20" Width="70" Content="外观"/>
- <Button Height="20" Width="70" Content="设置"/>
- </StackPanel>
- <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
- <Button Height="20" Width="20" Content="1"/>
- <Button Height="20" Width="20" Content="2"/>
- <Button Height="20" Width="20" Content="3"/>
- <Button Height="20" Width="20" Content="4"/>
- <Button Height="20" Width="20" Content="5"/>
- </StackPanel>
- <Grid Grid.Row="2" Grid.Column="0">
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="40"/>
- <ColumnDefinition/>
- </Grid.ColumnDefinitions>
- <StackPanel Grid.Column="0" Grid.Row="0">
- <Button Height="20" Content="1"/>
- <Button Height="20" Content="2"/>
- <Button Height="20" Content="3"/>
- <Button Height="20" Content="4"/>
- <Button Height="20" Content="5"/>
- <Button Height="20" Content="6"/>
- <Button Height="20" Content="7"/>
- <Button Height="20" Content="8"/>
- <Button Height="20" Content="9"/>
- <Button Height="20" Content="10"/>
- <Button Height="20" Content="11"/>
- <Button Height="20" Content="12"/>
- <Button Height="20" Content="13"/>
- <Button Height="20" Content="14"/>
- <Button Height="20" Content="15"/>
- <Button Height="20" Content="16"/>
- <Button Height="20" Content="17"/>
- </StackPanel>
- <TextBox Grid.Column="1" TextWrapping="Wrap"/>
- </Grid>
- </Grid>
- <Grid Grid.Row="3" Grid.Column="0">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="auto"/>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="1*"/>
- </Grid.ColumnDefinitions>
- <Button Grid.Column="0">Normal text file</Button>
- <Button Grid.Column="1">Length:1,125</Button>
- <Button Grid.Column="2">lines:26</Button>
- <Button Grid.Column="3">Ln:6 Col:57 Sel:3</Button>
- <Button Grid.Column="4">1</Button>
- <Button Grid.Column="5">Windows(CR LF)</Button>
- <Button Grid.Column="6">UTF-8-BOM</Button>
- <Button Grid.Column="7">INS</Button>
- </Grid>
- </Grid>
- </Window>
复制代码2-2 布局器的使用:
1、StackPanel 水平或垂直排列元素、Orientation 属性分别为:Horizontal / Verical
2、WrapPanel 水平或垂直排列元素、剩余控件不足会进行换行、换列的排布
3、DockPanel 根据容器的边界、元素进行 Dock.Top 、Left 、Right 、Bottom
4、Grid 类似 table表格
5、UniformGrid 指定行和列的数量,均匀有限的容器空间
6、Canvas 使用固定的坐标设置元素的位置
3、样式
样式写在:
< Window.Resources > 里的 < Style > 里 //定义
在标签里加属性Style: Style=“{StaticResource LoginStyle}” //使用
StaticResource 静态加载
DynamicResource 动态加载,在运行的时候,改变 xaml 文件内容,样式是会发生改变的 - <Window x:Class="WpfApp1.EditWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:WpfApp1"
- mc:Ignorable="d"
- Title="EditWindow" Height="450" Width="800">
- <Window.Resources>
- <Style TargetType="Button">
- <Setter Property="Background" Value="WhiteSmoke"/>
- <Setter Property="FontSize" Value="20"/>
- <Setter Property="Height" Value="50"/>
- <Setter Property="Width" Value="300"/>
- <Setter Property="Margin" Value="20,10"/>
- </Style>
- <Style x:Key="LoginStyle" TargetType="Button">
- <Setter Property="Background" Value="Green"/>
- <Setter Property="FontSize" Value="20"/>
- <Setter Property="Height" Value="50"/>
- <Setter Property="Width" Value="300"/>
- </Style>
- <Style x:Key="QuitStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button} }">
- <Setter Property="Background" Value="Red"/>
- </Style>
- </Window.Resources>
- <StackPanel>
- <Button Style="{StaticResource LoginStyle}" Content="登录"/>
- <Button Style="{DynamicResource QuitStyle}" Content="退出"/>
- <Button Content="忘记密码"/>
- </StackPanel>
- </Window>
复制代码继承:
- <Window x:Class="WpfApp1.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="登录界面" Height="270" Width="500" ResizeMode="NoResize">
- <Window.Resources>
- <Style x:Key="baseButtonStyle" TargetType="Button">
- <Setter Property="FontSize" Value="30"/>
- <Setter Property="Foreground" Value="Blue"/>
- </Style>
- <Style x:Key="defaultButtonStyle" TargetType="Button" BasedOn="{StaticResource baseButtonStyle}">
- <Setter Property="Width" Value="100"/>
- <Setter Property="Height" Value="50"/>
- </Style>
- </Window.Resources>
- <Grid>
- <Button Style="{StaticResource defaultButtonStyle}" Content="ghyu"/>
- </Grid>
- </Window>
复制代码4、添加资源字典
第一步:添加资源字典 xaml 文件
资源字典文件:Dictionary1.xaml - <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
- <Style TargetType="Button">
- <Setter Property="Background" Value="WhiteSmoke"/>
- <Setter Property="FontSize" Value="20"/>
- <Setter Property="Height" Value="50"/>
- <Setter Property="Width" Value="300"/>
- <Setter Property="Margin" Value="20,10"/>
- </Style>
- <Style x:Key="LoginStyle" TargetType="Button">
- <Setter Property="Background" Value="Green"/>
- <Setter Property="FontSize" Value="20"/>
- <Setter Property="Height" Value="50"/>
- <Setter Property="Width" Value="300"/>
- </Style>
- <Style x:Key="QuitStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button} }">
- <Setter Property="Background" Value="Red"/>
- </Style>
- </ResourceDictionary>
复制代码第二步:在 app.xml 文件中引入 资源字典文件- <ResourceDictionary Source="/WpfApp1;component/Dictionary1.xaml"/>
- 这里的 WpfApp1 是 命名空间
- Dictionary1.xaml 是 要加载的文件名
复制代码- <Application x:Class="WpfApp1.App"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:WpfApp1"
- StartupUri="EditWindow.xaml">
- <Application.Resources>
- <ResourceDictionary>
- <ResourceDictionary.MergedDictionaries>
- <ResourceDictionary Source="/WpfApp1;component/Dictionary1.xaml"/>
- </ResourceDictionary.MergedDictionaries>
- </ResourceDictionary>
- </Application.Resources>
- </Application>
复制代码第三步:在标签中,可以直接调用
- <Window x:Class="WpfApp1.EditWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:WpfApp1"
- mc:Ignorable="d"
- Title="EditWindow" Height="450" Width="800">
- <StackPanel>
- <Button Style="{StaticResource LoginStyle}" Content="登录"/>
- <Button Style="{DynamicResource QuitStyle}" Content="退出"/>
- <Button Content="忘记密码"/>
- </StackPanel>
- </Window>
复制代码5、用模板自定义一个带圆角的 Button 控件 及 触发器 的写法
- <ControlTemplate TargetType="Button">
复制代码里 TargetType=“Button” 和 TargetTye=“{x:Type Button}” 是一样的 - <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="6">
复制代码在这一行中,{TemplateBinding Background}" 表示从原 button 标签中去取 叫 Background 的属性 - <Window x:Class="WpfApp1.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:WpfApp1"
- mc:Ignorable="d"
- Title="123" Height="450" Width="800">
- <Grid>
- <Button Content="btn" Background="Red" BorderBrush="Black" FontSize="20" Width="200" Height="30" BorderThickness="3">
- <Button.Template>
- <ControlTemplate TargetType="Button">
- <Border x:Name="boder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="6">
- <TextBlock Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
- </Border>
- <ControlTemplate.Triggers>
- <Trigger Property="IsMouseOver" Value="True">
- <Setter TargetName="boder" Property="Background" Value="Black"/>
- </Trigger>
- <Trigger Property="IsPressed" Value="True">
- <Setter TargetName="boder" Property="Background" Value="WhiteSmoke"/>
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Button.Template>
- </Button>
- </Grid>
- </Window>
复制代码解读:
Grid: 一个布局容器,用于布局子元素。在这个例子中,它包含了一个 Button 控件。
Button: 一个按钮控件,具有以下属性:
Content=“btn”: 按钮的显示文本为 “btn”。
Background=“Red”: 按钮的背景颜色为红色。
BorderBrush=“Black”: 按钮的边框颜色为黑色。
FontSize=“20”: 按钮文本的字体大小为 20。
Width=“200”: 按钮的宽度为 200 像素。
Height=“30”: 按钮的高度为 30 像素。
BorderThickness=“3”: 按钮的边框厚度为 3 像素。
ControlTemplate: 定义了 Button 控件的外观模板。TargetType=“Button” 指定这个模板用于 Button 控件。
Border: 包含了按钮的主要视觉部分。
x:Name=“boder”: 给 Border 起了一个名字 boder,以便在触发器中引用。
Background=“{TemplateBinding Background}”: Border 的背景颜色绑定到按钮的 Background 属性。
BorderBrush=“{TemplateBinding BorderBrush}”: Border 的边框颜色绑定到按钮的 BorderBrush 属性。
BorderThickness=“{TemplateBinding BorderThickness}”: Border 的边框厚度绑定到按钮的 BorderThickness 属性。
CornerRadius=“6”: Border 的圆角半径设置为 6 像素,使边角有一定的圆润效果。
TextBlock: 显示按钮的文本内容。
Text=“{TemplateBinding Content}”: TextBlock 的文本绑定到按钮的 Content 属性。
HorizontalAlignment=“Center”: 文本在水平方向居中对齐。
VerticalAlignment=“Center”: 文本在垂直方向居中对齐.
5-2、触发器 的另一些实践- <Window x:Class="WpfApp1.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="登录界面" Height="270" Width="500">
- <Window.Resources>
- <Style x:Key="defaultButtonStyle" TargetType="Button">
- <Setter Property="Width" Value="100"/>
- <Setter Property="Height" Value="30"/>
- <Style.Triggers>
- <Trigger Property="IsMouseOver" Value="True">
- <Setter Property="Foreground" Value="Red"/>
- <Setter Property="FontSize" Value="30"/>
- </Trigger>
- <Trigger Property="IsMouseOver" Value="False">
- <Setter Property="Foreground" Value="Blue"/>
- <Setter Property="FontSize" Value="20"/>
- </Trigger>
- </Style.Triggers>
- </Style>
- <Style x:Key="defaultButtonStyle2" TargetType="Button">
- <Setter Property="Width" Value="100"/>
- <Setter Property="Height" Value="30"/>
- <Style.Triggers>
- <MultiTrigger>
- <MultiTrigger.Conditions>
- <Condition Property="IsMouseOver" Value="true"/>
- <Condition Property="IsFocused" Value="True"/>
- </MultiTrigger.Conditions>
- <MultiTrigger.Setters>
- <Setter Property="Foreground" Value="Red"/>
- </MultiTrigger.Setters>
- </MultiTrigger>
- </Style.Triggers>
- </Style>
- <Style x:Key="defaultButtonStyle3" TargetType="Button">
- <Setter Property="Width" Value="100"/>
- <Setter Property="Height" Value="30"/>
- <Style.Triggers>
- <EventTrigger RoutedEvent="Mouse.MouseEnter">
- <EventTrigger.Actions>
- <BeginStoryboard>
- <Storyboard>
- <DoubleAnimation Duration="0:0:0.2"
- Storyboard.TargetProperty="FontSize"
- To="30">
-
- </DoubleAnimation>
- </Storyboard>
- </BeginStoryboard>
- </EventTrigger.Actions>
- </EventTrigger>
- </Style.Triggers>
- </Style>
- </Window.Resources>
- <StackPanel>
- <Button Style="{StaticResource defaultButtonStyle}" Content="Hello"/>
- <Button Style="{StaticResource defaultButtonStyle2}" Content="Hello"/>
- <Button Style="{StaticResource defaultButtonStyle3}" Content="Hello"/>
- </StackPanel>
- </Window>
复制代码5-3、生成模板副本:
将 模板放在 资源字典中:
5-4、控件模板
5-5、数据模板
第一个例子:
第二个例子:
6、 button 的 和 点击事件 的写法:
6-2、添加点击事件的两种方式:
1 直接在 xaml 代码中进行添加
2 根据名字找到控件的 点击事件,在 cs 代码中添加
- <Window x:Class="WpfApp1.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:sys="clr-namespace:System;assembly=mscorlib"
- Title="MainWindow" Height="450" Width="800">
- <Window.Resources>
- <sys:String x:Key="stringHello">Hello WPF!</sys:String>
- </Window.Resources>
- <Grid>
- <TextBlock Height="24" Width="120" Background="LightBlue"
- Text="{StaticResource ResourceKey=stringHello}"/>
- </Grid>
- </Window>
复制代码7-1、控件间的属性绑定
- <Grid>
- <StackPanel>
- <Slider x:Name="slider" Margin="5"/>
- <TextBox
- Height="30"
- Margin="5"
- Text="{Binding ElementName=slider, Path=Value, Mode=OneTime}"/>
- <!--只进行一次绑定-->
- <TextBox
- Height="30"
- Margin="5"
-
- Text="{Binding ElementName=slider, Path=Value, Mode=OneWay}"/>
- <!--单向绑定-->
- <TextBox
- Height="30"
- Margin="5"
- Text="{Binding ElementName=slider, Path=Value}"/>
- <!--默认是双向绑定-->
- </StackPanel>
- </Grid>
复制代码7-2、一个简单的数据绑定的写法(属性的变更通知)
完成前 3 步,可以实现 数据从界面 向 代码的传递
完成后 2 步,可以实现 界面 向 代码层的数据传递
代码:
- <Window x:Class="WpfApp1.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:WpfApp1"
- mc:Ignorable="d"
- Title="登录界面" Height="270" Width="500" ResizeMode="NoResize">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="15"/>
- <RowDefinition Height="30"/>
- <RowDefinition Height="auto"/>
- <RowDefinition Height="5*"/>
- </Grid.RowDefinitions>
- <TextBox Grid.Row="1" Text="X6337TEB6----登录系统" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
- <Grid Grid.Row="2">
- <Grid.RowDefinitions>
- <RowDefinition Height="20"/>
- <RowDefinition Height="20"/>
- <RowDefinition Height="20"/>
- <RowDefinition Height="27"/>
- </Grid.RowDefinitions>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="1*"/>
- <ColumnDefinition Width="auto"/>
- <ColumnDefinition Width="150"/>
- <ColumnDefinition Width="1*"/>
- </Grid.ColumnDefinitions>
- <TextBlock Grid.Row="0" Grid.Column="1" Text="用户名"/>
- <TextBox Text ="{Binding UserName}" Grid.Row="0" Grid.Column="2" Margin="3,2"/>
- <TextBlock Grid.Row="1" Grid.Column="1" Text="密码"/>
- <TextBox Text="{Binding PassWord}" Grid.Row="1" Grid.Column="2" Margin="3,2"/>
- <CheckBox Grid.ColumnSpan="2" Grid.Row="2" Grid.Column="1" Content="记住密码"/>
- <Button Grid.ColumnSpan="2" Grid.Row="3" Grid.Column="1" Content="登录" Margin="3,1" Click="Button_Click"/>
- </Grid>
- </Grid>
- </Window>
复制代码- using System;
- using System.ComponentModel;
- using System.Windows;
- namespace WpfApp1
- {
- /// <summary>
- /// MainWindow.xaml 的交互逻辑
- /// </summary>
- public partial class MainWindow : Window,INotifyPropertyChanged
- {
- #region 数据绑定的固定写法
- private string _userName;
- private string _passWord;
- public string UserName {
- get { return _userName; }
- set
- {
- _userName = value;
- RaisePropertyChanged("UserName");
- }
- }
- public string PassWord
- {
- get { return _passWord; }
- set
- {
- _passWord = value;
- RaisePropertyChanged("PassWord");
- }
- }
- public event PropertyChangedEventHandler PropertyChanged;
- private void RaisePropertyChanged(string propertyName)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
- #endregion
- public MainWindow()
- {
- InitializeComponent();
- this.DataContext = this;
- }
- /// <summary>
- /// 登录按钮
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- Console.WriteLine($"{UserName}-{PassWord}");
- UserName = "Admin";
- PassWord = "123";
- }
- }
- }
复制代码8、MVVM(与 7 是同一个界面)
MVVM是为里前后端的分离
MVVM与MVC,VM 是对 C 的升级(依靠的是 双向的数据属性 和 单向的命令属性)
V 的修改 不会影响到 其他部分代码的编译
MVVM 和 MVC 的区别
MVVM
M Model
V View
VM ViewModel
MVC
M Model
V View
C Control
8-1.1 带参的方法的写法:
传入 Tag- <Button Grid.Row="0" Command="{Binding ClickBtn}" Tag="a" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Tag}">a</Button>
复制代码- public ICommand ClickBtn
- {
- get
- {
- return new ExecuteCommond((param) =>
- {
- // param 是 CommandParameter 传递的值
- string tag = param as string;
- Console.WriteLine($"Tag: {tag}");
- });
- }
- }
复制代码传入控件自身- <Button Grid.Row="0" Command="{Binding ClickBtn}" Tag="a" CommandParameter="{Binding RelativeSource={RelativeSource Self}}">a</Button>
复制代码- public ICommand ClickBtn
- {
- get
- {
- return new ExecuteCommond((param) =>
- {
- if (param is Button button)
- {
- var tag = button.Tag; // 获取按钮的Tag属性
- Console.WriteLine($"Tag: {tag}");
- }
- });
- }
- }
复制代码多种入参的 ICommand 的实现- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Input;
- namespace QIPWaterDeal.ViewModel
- {
- public class ExecuteCommond : ICommand
- {
- /// <summary>
- /// 判断命令是否可以执行
- /// </summary>
- private readonly Func<bool> _canExecute;
- /// <summary>
- /// 执行无参数的操作
- /// </summary>
- private readonly Action _execute;
- /// <summary>
- /// 执行带参数的操作
- /// </summary>
- private readonly Action<object> _executeWithParameter;
- /// <summary>
- /// 构造方法(无参数版本)
- /// </summary>
- public ExecuteCommond(Action execute, Func<bool> canExecute = null)
- {
- _execute = execute;
- _canExecute = canExecute;
- }
- /// <summary>
- /// 构造方法(带参数版本)
- /// </summary>
- public ExecuteCommond(Action<object> executeWithParameter, Func<bool> canExecute = null)
- {
- _executeWithParameter = executeWithParameter;
- _canExecute = canExecute;
- }
- public event EventHandler CanExecuteChanged;
- /// <summary>
- /// 是否可以执行命令
- /// </summary>
- public bool CanExecute(object parameter)
- {
- return _canExecute == null || _canExecute();
- }
- /// <summary>
- /// 执行命令
- /// </summary>
- public void Execute(object parameter)
- {
- if (_execute != null)
- {
- _execute.Invoke();
- }
- else if (_executeWithParameter != null)
- {
- _executeWithParameter.Invoke(parameter);
- }
- }
- /// <summary>
- /// 通知CanExecute状态发生变化
- /// </summary>
- public void RaiseCanExecuteChanged()
- {
- CanExecuteChanged?.Invoke(this, EventArgs.Empty);
- }
- }
- }
复制代码8-2 MVVM的另一种实践(对 进行包装)
一个实际的例子
MainWindow.xml - <Window x:Class="WpfApp1.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="登录界面" Height="270" Width="500" ResizeMode="NoResize">
- <Grid>
- <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
- <TextBox x:Name="input1" Width="100" Height="24" Margin="3" Text="{Binding Input1}"></TextBox>
- <TextBox x:Name="input2" Width="100" Height="24" Margin="3" Text="{Binding Input2}"></TextBox>
- <TextBox x:Name="input3" Width="100" Height="24" Margin="3" Text="{Binding Input3}"></TextBox>
- <Button x:Name="btn1" Width="100" Height="24" Margin="3" Content="Add" Command="{Binding AddCommand}"></Button>
- </StackPanel>
- </Grid>
- </Window>
复制代码NotificationObject - using System.ComponentModel;
- namespace WpfApp1
- {
- /// <summary>
- /// VM 的基类
- /// </summary>
- public class NotificationObject:INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged;
- public void RaisePropertyChange(string propertyName)
- {
- if(this.PropertyChanged != null)
- {
- this.PropertyChanged.Invoke(this,new PropertyChangedEventArgs(propertyName));
- }
- }
- }
- }
复制代码DelegateCommand - using System;
- using System.Windows.Input;
- namespace WpfApp1
- {
- public class DelegateCommand:ICommand
- {
- public bool CanExecute(object parameter)
- {
- if(this.CanExecuteFunc == null)
- {
- return true;
- }
- return this.CanExecuteFunc(parameter);
- }
- public event EventHandler CanExecuteChanged;
- public void Execute(object parameter)
- {
- if(this.ExecuteAction == null)
- {
- return;
- }
- this.ExecuteAction(parameter);
- }
- public Action<object> ExecuteAction { get; set; }
- public Func<object,bool> CanExecuteFunc { get; set; }
- }
- }
复制代码MainWindowViewModel - using System;
- namespace WpfApp1
- {
- internal class MainWindowViewModel : NotificationObject
- {
- #region 数据属性
- private double input1;
- public double Input1
- {
- get
- {
- return input1;
- }
- set
- {
- input1 = value;
- this.RaisePropertyChange(nameof(Input1));
- }
- }
- private double input2;
- public double Input2
- {
- get
- {
- return input2;
- }
- set
- {
- input2 = value;
- this.RaisePropertyChange(nameof(Input2));
- }
- }
- private double input3;
- public double Input3 {
- get {
- return input3;
- }
- set {
- input3 = value;
- this.RaisePropertyChange(nameof(Input3));
- }
- }
- #endregion
- #region 命令属性
- public DelegateCommand AddCommand { get; set; }
- private void Add(object parameter)
- {
- this.Input3 = this.Input1 + this.Input2;
- }
- public MainWindowViewModel()
- {
- this.AddCommand = new DelegateCommand();
- this.AddCommand.ExecuteAction = new Action<object>(this.Add);
- }
- #endregion
- }
- }
复制代码8-3、利用 特性(反射),优化数据变更通知(接口)的写法
9、写一个自定义控件(添加 自定义 依赖属性)
字典资源
加入字典资源
继承 Button 的自定义控件
使用:
10、导入程序集和引用其中的名称空间:
然后选 带 Framework 的
- <UserControl x:Class="WpfControlLibrary3.UserControl1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:local="clr-namespace:WpfControlLibrary3"
- mc:Ignorable="d"
- d:DesignHeight="160" d:DesignWidth="240">
- <Grid>
- <Canvas>
- <Label Canvas.Left="12" Canvas.Top="12" Content="第一部分" Height="28" Name="label1"/>
- <Label Canvas.Left="12" Canvas.Top="46" Content="第二部分" Height="28" Name="label2"/>
- <Label Canvas.Left="12" Canvas.Top="80" Content="第三部分" Height="28" Name="label3"/>
- <TextBox Canvas.Left="88" Canvas.Top="14" Height="23" Name="textBox1" Width="140"/>
- <TextBox Canvas.Left="88" Canvas.Top="48" Height="23" Name="textBox2" Width="140"/>
- <TextBox Canvas.Left="88" Canvas.Top="82" Height="23" Name="textBox3" Width="140"/>
- <Button Canvas.Left="88" Canvas.Top="125" Content="计算" Height="23" Name="button1" Width="140" Click="button_Click"/>
- </Canvas>
- </Grid>
- </UserControl>
复制代码添加引用:
11、一些 x 命名空间的使用
x:Class
x:ClassModifier
x:Name
x:FieldModifier
12、在WPF中加载 Winform 的 Form
1、在wpf 中添加引用
System.Windows.Forms.Integration
和
System.Windows.Forms.Integration
注:System.Windows.Forms.Integration 在 Net Formwork 4.7.2 中叫 WindowsFormsIntegration
2、创建用户控件
在wpf 项目中创建 winform 控件 - using System.Windows.Forms;
- using WindowsFormsControlLibrary1;
- namespace WpfApp1
- {
- public partial class UserControl1 : UserControl
- {
- private Form1 _form1;
- public UserControl1()
- {
- InitializeComponent();
- _form1 = new Form1();
- _form1.TopLevel = false;
- _form1.Dock = DockStyle.Fill;
- this.Controls.Add(_form1);
- _form1.Show();
- }
- }
- }
复制代码在 主界面中 WindowsFormsHost 加入标签,在代码中加载 Winform 的控件,借助Winform控件 加载 winform 窗体 - <Grid>
- <WindowsFormsHost Name="windowsFormsHost" />
- </Grid>
复制代码- using System.Windows;
- namespace WpfApp1
- {
- /// <summary>
- /// MainWindow.xaml 的交互逻辑
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- UserControl1 userControl1 = new UserControl1();
- windowsFormsHost.Child = userControl1;
- }
- }
- }
复制代码13、动画
动画有三种:
线性动画:DouleAnmim
关键帧动画:DoubleAnimationUsingkeyFrams
路径动画:DoubleAnimationUsingPath
- <Grid>
- <StackPanel>
- <Button x:Name="btn" Width="100" Height="24" Content="带动画的按钮" Click="Button_Click"/>
- <Button x:Name="btn2" Width="100" Height="24" Content="带动画的按钮" Click="Button_Click2"/>
- <Button x:Name="btn3" Width="100" Height="24" Content="带动画的按钮" Click="Button_Click3"/>
- </StackPanel>
- </Grid>
复制代码- #define C
- using System;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Media.Animation;
- namespace WpfApp1
- {
- /// <summary>
- /// MainWindow.xaml 的交互逻辑
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- }
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- //创建一个双精度的动画
- DoubleAnimation animation = new DoubleAnimation();
- animation.From = btn.Width;//设置动画的初始值
- animation.To = btn.Width - 30;//设置动画的结束值
- animation.Duration = TimeSpan.FromSeconds(2);//设置动画的持续时间
- //在当前按钮上实行该动画
- btn.BeginAnimation(Button.WidthProperty,
- animation);
- }
- private void Button_Click2(object sender, RoutedEventArgs e)
- {
- //创建一个双精度的动画
- DoubleAnimation animation = new DoubleAnimation();
- animation.From = btn2.Width;//设置动画的初始值
- animation.To = btn2.Width - 30;//设置动画的结束值
- animation.Duration = TimeSpan.FromSeconds(2);//设置动画的持续时间
- animation.AutoReverse = true; //是否往返执行
- animation.RepeatBehavior = RepeatBehavior.Forever; //执行周期
- //在当前按钮上实行该动画
- btn2.BeginAnimation(Button.WidthProperty,
- animation);
- }
- private void Button_Click3(object sender, RoutedEventArgs e)
- {
- //创建一个双精度的动画
- DoubleAnimation animation = new DoubleAnimation();
- animation.From = btn3.Width;//设置动画的初始值
- animation.To = btn3.Width - 30;//设置动画的结束值
- animation.Duration = TimeSpan.FromSeconds(2);//设置动画的持续时间
- animation.AutoReverse = true; //是否往返执行
- animation.RepeatBehavior = new RepeatBehavior(5);//重复5次
- animation.Completed += Animation_Completed;//动画结束的回调
- //在当前按钮上实行该动画
- btn3.BeginAnimation(Button.WidthProperty,
- animation);
- }
- private void Animation_Completed(object sender,EventArgs e)
- {
- btn3.Content = "动画已完成";
- }
- }
- }
复制代码14、WPF 和 Prism
其他
1、获取当前文件目录- string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
复制代码 |