[C.C++] C#之上位机开发---------C#通信库及WPF的简单实践

318 0
Honkers 2026-5-15 02:18:59 来自手机 | 显示全部楼层 |阅读模式

〇、上位机,分层架构

界面层

要实现的功能:
展示数据
获取数据
发送数据

数据层

要实现的功能:
转换数据
打包数据
存取数据

通信层

要实现的功能:
打开连接
关闭连接
读取数据
写入数据

实体类

作用:
封装数据、传递数据

工具类

一、通信介绍及简单测试

一、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>.简单 测试下 连接-读写
  1. using S7.Net;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Drawing;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. using System.Windows.Forms;
  11. namespace WindowsFormsApp1
  12. {
  13. public partial class Form1 : Form
  14. {
  15. public Form1()
  16. {
  17. InitializeComponent();
  18. Test();
  19. }
  20. Plc plc = null;
  21. private void Test()
  22. {
  23. plc = new Plc(CpuType.S7200Smart, "192.168.2.1", 0, 0);
  24. plc.Open();
  25. //读取数据
  26. object data = plc.Read("M20.0");
  27. this.label1.Text = data.ToString();
  28. //写入数据
  29. plc.Write("M20.0", false);
  30. //不支持V区直接操作,需要映射成DB1
  31. plc.Write("DB1.DBX2000.0", true);
  32. plc.Close();
  33. }
  34. }
  35. }
复制代码
<2>.简单 的封装下
  1. using S7.Net;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace WindowsFormsApp1
  8. {
  9. public class S7NetLib
  10. {
  11. private Plc s7netlib = null; //字段
  12. //属性
  13. public CpuType CPUType { get;set; }
  14. public string IPAddress { get; set; }
  15. public short Rack { get; set; }
  16. public short Slot { get; set; }
  17. //构造函数,初始化连接 所需的变量
  18. public S7NetLib(CpuType cpuType,string ip,short rack,short slot)
  19. {
  20. this.CPUType = cpuType;
  21. this.IPAddress = ip;
  22. this.Rack = rack;
  23. this.Slot = slot;
  24. }
  25. /// <summary>
  26. /// 打开PLC连接
  27. /// </summary>
  28. public void OpenPLC()
  29. {
  30. if(this.s7netlib == null)
  31. {
  32. s7netlib = new Plc(CPUType,IPAddress,Rack,Slot);
  33. }
  34. if (!this.s7netlib.IsConnected)
  35. {
  36. s7netlib.ReadTimeout = 1000;//设置超时时间
  37. s7netlib.WriteTimeout = 1000;
  38. s7netlib.Open();//建立连接
  39. }
  40. }
  41. /// <summary>
  42. /// 关闭PLC连接
  43. /// </summary>
  44. public void ClosePLC()
  45. {
  46. if(null != this.s7netlib && this.s7netlib.IsConnected)
  47. {
  48. this.s7netlib.Close();
  49. }
  50. }
  51. /// <summary>
  52. /// 给plc单个变量写入数据
  53. /// </summary>
  54. /// <param name="varAddress">写到那里去</param>
  55. /// <param name="varValue">写入的值</param>
  56. public void WriteDataToPLC(string varAddress, object varValue)
  57. {
  58. OpenPLC();
  59. lock (this)
  60. {
  61. this.s7netlib.Write(varAddress, varValue);
  62. }
  63. }
  64. /// <summary>
  65. /// 读取一段数据
  66. /// </summary>
  67. /// <param name="dataType">存储区类型</param>
  68. /// <param name="db">DB号</param>
  69. /// <param name="startByteAdr">开始字节地址</param>
  70. /// <param name="count">字节数量</param>
  71. /// <returns>字节数组</returns>
  72. public byte[] ReadDataFromPLC(DataType dataType,int db,int startByteAdr,int count)
  73. {
  74. lock (this)
  75. {
  76. byte[] bytes = this.s7netlib.ReadBytes(dataType,db,startByteAdr,count);
  77. return bytes;
  78. }
  79. }
  80. }
  81. }
复制代码
  1. using S7.Net;
  2. using System.Windows.Forms;
  3. namespace WindowsFormsApp1
  4. {
  5. public partial class Form1 : Form
  6. {
  7. public Form1()
  8. {
  9. InitializeComponent();
  10. Test();
  11. }
  12. private void Test()
  13. {
  14. S7NetLib plc = new S7NetLib(CpuType.S7200, "192.168.2.1", 0, 0);
  15. plc.WriteDataToPLC("M2.2", true);
  16. byte[] dataBytes = null;
  17. dataBytes = plc.ReadDataFromPLC(DataType.DataBlock, 1, 0, 10);
  18. }
  19. }
  20. }
复制代码

一次读一个PDU 的长度,不同 CPU的 PDU 的长度不同

2、C# + SQLSERVER

〇、环境

软件的安装(服务器端、客户端)

服务器端:
SQL Sever 下载地址:
https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads

客户端

服务器端的操作:


客户端的操作:


两种连接方式:

SQL Server 的连接配置(增加使用密码登录的用户):

第一步:



第二步:


第三步: 重新启动,在连接登录
.

开启远程用户登录的方式(使用 IP 和 端口号)

第一步:

第二步:


第三步:重启服务
右键我的电脑,点击属性

第四步:最后登录

一、操作软件:

  1. SQL Server Management Studio
复制代码

1、两种连接方式:

2、新建表



然后 ctrl+s 保存

3、添加数据

4、查询数据


注:注释是在前面加 –

5、解决不允许保存的弹窗

6、设置主键

7、更改数据(增加、删除、需改)
  1. --查
  2. select * from UserT
  3. --存
  4. --新增
  5. insert into UserT(UserName,Password,NickName) values('111','222','333')
  6. --删除
  7. delete from UserT where UserName='111'
  8. delete from UserT where UserName='111' and Password='888'
  9. --修改
  10. update UserT set UserName='a' where UserName='111'
复制代码

到某个指定的数据库

  1. use QingTongXiaWaterPlant_test
  2. go
复制代码

修改某一段名的数据类型:

  1. use QingTongXiaWaterPlant_test
  2. go
  3. alter table dbo.WaterFlowData alter column d17 float null;
复制代码

二、数据库数据类型

三、数据库的约束

四、运算符:

五、SQL 语句

(1)、搜索当前存在哪些数据库:
  1. select * from sysdatabases
复制代码
(2)、创建数据库:

1、创建数据库所在的文件夹


建好的文件

2、执行 sql语句

  1. use master
  2. go
  3. if exists(select * from sysdatabases where name='MISDB') --如果原来存在这个数据库,则进行删除
  4. drop database MISDB
  5. go
  6. --创建数据库
  7. create database MISDB
  8. on primary
  9. (
  10. name='MISDB_MData',--必须唯一
  11. filename='D:\DB\MISDB_MData.mdf', --物理文件名,主存储文件
  12. size=30MB,filegrowth=10MB
  13. )
  14. ,
  15. (
  16. name='MISDB_nData',
  17. filename='D:\DB\DBMISDB_nData.ndf', --次存储文件
  18. size=20MB,
  19. filegrowth=10MB
  20. )
  21. log on
  22. (
  23. name='MISDB_log1',
  24. filename='D:\DB\MISDB_log1.ldf', --日志文件
  25. size=20MB,
  26. filegrowth=10MB
  27. )
  28. ,
  29. (
  30. name='MISDB_log2',
  31. filename='D:\DB\MISDB_log2.ldf', --日志文件
  32. size=20MB,
  33. filegrowth=10MB
  34. )
复制代码
(3)、创建表:
  1. --创建数据表,是在指定的数据库里面
  2. use MISDB
  3. go
  4. if exists(select * from sysobjects where name='Department') --如果已经有了 Department 表则对其进行删除
  5. drop table Department
  6. go
  7. create table Department
  8. (
  9. DepartmentId int identity(10,1)primary key,--部门字段值,由系统自动生成,从10开始,每次增加1 primary key 是主键的标识
  10. DepartmentName varchar(50)not null
  11. )
  12. go
  13. if exists(select * from sysobjects where name='Post') --如果已经有了 Post 表则对其进行删除
  14. drop table Post
  15. go
  16. create table Post
  17. (
  18. PostId int identity(10,1)primary key,
  19. PostName varchar(50) not null
  20. )
  21. go
  22. if exists(select * from sysobjects where name='Employee')
  23. drop table Employee
  24. go
  25. create table Employee
  26. (
  27. EmplyeeId int identity(100,1) primary key,
  28. EmplyeeName varchar(50) not null,
  29. Gender char(2) not null check(Gender='男' or Gender='女'),
  30. NowAddress nvarchar(100) default('地址不详'),
  31. IdNo char(18) not null check(len(Idno)=18),--检查约束
  32. WeiXinNumber varchar(20)not null,
  33. PhoneNumber varchar(50) not null,
  34. OtherWork nvarchar(50) not null,
  35. EntryDate datetime not null,
  36. PostId int references Post(PostId), --外键引用
  37. DepartmentId int references Department(DepartmentId) --外键引用
  38. )
  39. go
复制代码
(4)、简单的 增、删、改、查
  1. --查
  2. select * from UserT
  3. --存
  4. --新增
  5. insert into UserT(UserName,Password,NickName) values('111','222','333')
  6. --删除
  7. delete from UserT where UserName='111'
  8. delete from UserT where UserName='111' and Password='888'
  9. --修改
  10. update UserT set UserName='a' where UserName='111'
复制代码

到某个指定的数据库

  1. use QingTongXiaWaterPlant_test
  2. go
复制代码

修改某一段名的数据类型:

  1. use QingTongXiaWaterPlant_test
  2. go
  3. alter table dbo.WaterFlowData alter column d17 float null;
复制代码
(5)、增加
  1. use MISDB
  2. go
  3. select * from Department
  4. select * from Post
  5. select * from Employee
  6. insert into Department(DepartmentName)
  7. values('开发部'),('测试部'),('财务部'),('人事部')
  8. inSert into Post(PostName)
  9. values('软件工程师'),('测试工程师'),('实施工程师'),('财务经理'),('人事经理')
  10. insert into Employee(EmployeeName,Gender,NowAddress,IdNo,
  11. WeiXinNumber,PhoneNumber,OtherWork,EntryDate,PostId,DepartmentId)values
  12. ('Kiter10','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  13. ('Kiter11','男','北京','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  14. ('Kiter12','男','福州','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  15. ('Kiter13','男','西安','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  16. ('Kiter14','男','苏州','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  17. ('Kiter15','男','咸阳','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  18. ('Kiter16','男','永寿','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  19. ('Kiter17','女','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  20. ('Kiter18','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  21. ('Kiter19','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  22. ('Kiter20','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  23. ('Kiter21','女','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  24. ('Kiter22','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  25. ('Kiter23','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  26. ('Kiter24','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  27. ('Kiter25','女','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  28. ('Kiter26','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12),
  29. ('Kiter27','男','天津','123456789123456789','tt00','36954215478','没有','2024-09-09',10,12)
复制代码
(6)、删除
  1. delete from Employee where EmployId=112
  2. delete from Employee where EmployId>=117
复制代码
(7)、修改
  1. update Employee set EmployeeName='小王',NowAddress='天津X'where EmployId=101
复制代码
(8)、查询(及内查询)
  1. select * from Department
  2. select * from Post
  3. select * from employee
  4. --条件查询
  5. select EmployId,EmployeeName,Gender,NowAddress,PhoneNumber
  6. from Employee where EmployId>=105 and EmployId<=115 and gender='女'
  7. update Employee set EmployeeName='小王',NowAddress='天津X'where EmployId=101
  8. delete from Employee where EmployId=112
  9. delete from Employee where EmployId>=117
  10. --内连接查询
  11. select EmployId,EmployeeName,PhoneNumber,Post.PostId,Post.PostName
  12. from Employee
  13. inner join Post on Post.PostId=Employee.PostId
  14. --内连接查询
  15. select EmployId,EmployeeName,PhoneNumber,
  16. Post.PostId,PostName,DepartmentName
  17. from Employee
  18. inner join Post on Post.PostId=Employee.PostId
  19. inner join Department on Department.DepartmentId=Employee.DepartmentId
  20. --聚合查询
  21. select count(*) as 员工总数 from Employee
  22. select 编号平均数=avg(EmployId)from Employee
  23. select 编号最小值=min(EmployId)from Employee
  24. select 编号最大值=max(EmployId)from Employee
复制代码
(9)、给表增加列:
  1. ALTER TABLE Employees
  2. ADD
  3. Column1 INT,
  4. Column2 NVARCHAR(50),
  5. Column3 DATETIME;
复制代码
(10)、存储过程:

新建

  1. CREATE PROCEDURE JiaYao
  2. -- 输入参数 执行哪个加药
  3. @Index varchar(32) ='',
  4. @C1_DangLiang real=0,
  5. -- 输出
  6. @dosage real output
  7. AS
  8. BEGIN
  9. -- 为了不返回 每条sql 影响多少条记录的信息
  10. SET NOCOUNT ON
  11. select
  12. avg(data_js_d1) as js_cod,
  13. from RealData
  14. if @Index='PAC1'
  15. begin
  16. set @dosage =js_cod/3;
  17. end
  18. if @Index='PAC2'
  19. begin
  20. set @dosage =js_cod/2;
  21. end
  22. END
复制代码

修改

  1. ALTER PROCEDURE JiaYao
  2. -- 输入参数 执行哪个加药
  3. @Index varchar(32) ='',
  4. @C1_DangLiang real=0,
  5. -- 输出
  6. @dosage real output
  7. AS
  8. BEGIN
  9. -- 为了不返回 每条sql 影响多少条记录的信息
  10. SET NOCOUNT ON
  11. select
  12. avg(data_js_d1) as js_cod,
  13. from RealData
  14. if @Index='PAC1'
  15. begin
  16. set @dosage =js_cod/3;
  17. end
  18. if @Index='PAC2'
  19. begin
  20. set @dosage =js_cod/2;
  21. end
  22. END
复制代码

执行的sql

  1. DECLARE @dosage real;
  2. EXEC JiaYao @dosage=1.3,
  3. -- 输入参数 执行哪个加药
  4. @Index ='PAC1',
复制代码

六、在C#中 使用,SQLServer 数据库




  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data.SqlClient;
  4. using System.Data;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using System.Diagnostics;
  9. using System.Management.Instrumentation;
  10. namespace ConsoleApp1
  11. {
  12. public class SqlServer
  13. {
  14. /** 建立连接所需要的信息
  15. * Server 是服务器的地址
  16. * DataBase 是数据库的名称
  17. * Uid 是登录的用户名
  18. * Pwd 是用户名的密码
  19. */
  20. //private string connString1 = "Server=E2JMKGABJ62SR4X\\SQLEXPRESS;DataBase=MISDB;Uid=sa;Pwd=123456";
  21. //private string connString1 = "Server=192.168.31.130,1433\\SQLEXPRESS;DataBase=MISDB;Uid=sa;Pwd=123456";
  22. private string connString1 = "Server=192.168.31.130,1433;DataBase=MISDB;Uid=sa;Pwd=123456";
  23. //建立连接的方法
  24. public void ConnectDB()
  25. {
  26. SqlConnection conn = new SqlConnection(connString1);
  27. conn.Open();
  28. if (conn.State == System.Data.ConnectionState.Open)
  29. {
  30. Console.WriteLine("连接成功");
  31. }
  32. conn.Close();
  33. if (ConnectionState.Closed == conn.State)
  34. {
  35. Console.WriteLine("连接关闭");
  36. }
  37. }
  38. //插入语句的写法
  39. public void Insert()
  40. {
  41. //创建建立连接的对象 -- SqlConnection
  42. SqlConnection conn = new SqlConnection(connString1);
  43. //sql语句,
  44. 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)";
  45. //创建执行 sql 语句的对象
  46. SqlCommand cmd = new SqlCommand(sql, conn);
  47. //连接
  48. conn.Open();
  49. //执行sql语句
  50. int result = cmd.ExecuteNonQuery();
  51. //断开连接
  52. conn.Close();
  53. Console.WriteLine("受影响的行数:"+result);
  54. }
  55. //变更数据的写法
  56. public void Update()
  57. {
  58. //创建建立连接的对象 -- SqlConnection
  59. SqlConnection conn = new SqlConnection(connString1);
  60. //sql语句
  61. string sql = "update Employee set EmployeeName='UBM'where EmployId=121";
  62. //创建执行 sql 语句的对象
  63. SqlCommand cmd = new SqlCommand(sql, conn);
  64. //连接
  65. conn.Open();
  66. //执行sql语句
  67. int result = cmd.ExecuteNonQuery();
  68. //断开连接
  69. conn.Close();
  70. Console.WriteLine("受影响的行数:" + result);
  71. }
  72. //删除表中的记录
  73. public void Delete()
  74. {
  75. //创建建立连接的对象 -- SqlConnection
  76. SqlConnection conn = new SqlConnection(connString1);
  77. //要执行的 sql 语句
  78. string sql = "delete from Employee where EmployId=102";
  79. //实例化 要执行 sql的对象 -- SqlCommand
  80. SqlCommand cmd = new SqlCommand(sql, conn);
  81. //建立连接
  82. conn.Open();
  83. //执行 sql语句
  84. int result = cmd.ExecuteNonQuery();
  85. //关闭练级
  86. conn.Close();
  87. Console.WriteLine("受影响的行数:" + result);
  88. }
  89. //执行查询结果为1个的 sql 语句
  90. public void GetSingleResult()
  91. {
  92. //创建建立连接的对象 -- SqlConnection
  93. SqlConnection conn = new SqlConnection(connString1);
  94. //要执行的 sql 语句
  95. string sql = "select EmployeeName from Employee where EmployId=101";
  96. //实例化 要执行 sql的对象 -- SqlCommand
  97. SqlCommand cmd = new SqlCommand(sql, conn);
  98. //建立连接
  99. conn.Open();
  100. //执行 sql语句 ExecuteScalar 是执行只有一个返回结果的sql 语句
  101. object result = cmd.ExecuteScalar();
  102. //关闭连接
  103. conn.Close();
  104. Console.WriteLine(result);
  105. }
  106. //执行查询结果为1个的 sql 语句
  107. public void GetSingleResult2()
  108. {
  109. //创建建立连接的对象 -- SqlConnection
  110. SqlConnection conn = new SqlConnection(connString1);
  111. //要执行的 sql 语句
  112. string sql = "select 员工总数=count(*)from Employee";
  113. //实例化 要执行 sql的对象 -- SqlCommand
  114. SqlCommand cmd = new SqlCommand(sql, conn);
  115. //建立连接
  116. conn.Open();
  117. //执行 sql语句 ExecuteScalar 是执行只有一个返回结果的sql 语句
  118. object result = cmd.ExecuteScalar();
  119. int count = (int)result;//如果程序需要使用具体数据类型,就可以转换
  120. //关闭连接
  121. conn.Close();
  122. Console.WriteLine(count);
  123. }
  124. //用 ExecuteScalar 来执行 插入操作,返回看新增的记录是第几条的
  125. public void GetSingleResult3()
  126. {
  127. SqlConnection conn = new SqlConnection(connString1);
  128. string sql = "insert into Employee(EmployeeName,Gender," +
  129. "NowAddress,IdNo,WeiXinNumber,PhoneNumber,OtherWork," +
  130. "EntryDate,PostId,DepartmentId)"+
  131. "Values('Kiter50','男','北京','123456789123456789','qwer1','96325451784','没有','2024-11-07',10,12)";
  132. sql += ";select @@Identity";
  133. SqlCommand cmd = new SqlCommand (sql,conn);
  134. conn.Open();
  135. int result = Convert.ToInt32(cmd.ExecuteScalar());
  136. conn.Close();
  137. Console.WriteLine("编号:"+result);
  138. }
  139. //读取多条记录 (查询的 多个表)
  140. public void GetReaderList()
  141. {
  142. //创建建立连接的对象 -- SqlConnection
  143. SqlConnection conn = new SqlConnection(connString1);
  144. //要执行的 sql 语句
  145. string sql = "select EmployeeName,Gender,NowAddress from Employee";
  146. //实例化 要执行 sql的对象 -- SqlCommand
  147. SqlCommand cmd = new SqlCommand(sql, conn);
  148. //建立连接
  149. conn.Open();
  150. //执行结果集查询
  151. SqlDataReader reader = cmd.ExecuteReader();
  152. //逐行读取
  153. while (reader.Read())
  154. {
  155. string result = reader["EmployeeName"].ToString() + reader["Gender"] + reader["NowAddress"];
  156. Console.WriteLine(result);
  157. }
  158. //释放资源
  159. reader.Close(); //关闭读取器
  160. conn.Close(); //关闭连接
  161. }
  162. //读取多条记录(查询的是多个表)
  163. public void GetReaderList2()
  164. {
  165. //创建建立连接的对象 -- SqlConnection
  166. SqlConnection conn = new SqlConnection(connString1);
  167. //要执行的 sql 语句
  168. string sql = "select EmployeeName,Gender,NowAddress from Employee";
  169. sql += ";select DepartmentId,DepartmentName from Department";
  170. //实例化 要执行 sql的对象 -- SqlCommand
  171. SqlCommand cmd = new SqlCommand(sql, conn);
  172. //建立连接
  173. conn.Open();
  174. //执行结果集查询
  175. SqlDataReader reader = cmd.ExecuteReader();
  176. //逐行读取
  177. while (reader.Read())
  178. {
  179. string result = reader["EmployeeName"].ToString()+"\t"+reader[1]+"\t"+reader["NowAddress"];
  180. Console.WriteLine(result);
  181. }
  182. Console.WriteLine("*************");
  183. if (reader.NextResult())
  184. {
  185. while (reader.Read())
  186. {
  187. Console.WriteLine($"{reader["DepartmentId"]}\t{reader["DepartmentName"]}");
  188. }
  189. }
  190. //关闭读取器
  191. reader.Close();
  192. //关闭连接
  193. conn.Close();
  194. }
  195. //使用 DataSet 和 SqlDataAdapter 读取多条记录
  196. public void GetDataSet1()
  197. {
  198. //创建连接对象
  199. SqlConnection conn = new SqlConnection(connString1);
  200. //sql 语句
  201. string sql = "select EmployeeName,Gender,NowAddress from Employee";
  202. //创建执行sql的对象
  203. SqlCommand cmd = new SqlCommand(sql, conn);
  204. //打开连接
  205. conn.Open();
  206. //创建数据适配器对象
  207. SqlDataAdapter da = new SqlDataAdapter(cmd);
  208. //创建一个数据集对象
  209. DataSet ds = new DataSet();
  210. //将查询到到结果填入到,内存中(DataSet)
  211. da.Fill(ds);
  212. //关闭连接
  213. conn.Close();
  214. //读取数据
  215. DataTable dt = ds.Tables[0];
  216. foreach(DataRow dr in dt.Rows)
  217. {
  218. Console.WriteLine($"{dr["EmployeeName"]}\t{dr["Gender"]}\t{dr["NowAddress"]}");
  219. }
  220. }
  221. //使用 DataSet 和 SqlDataAdapter 读取多条记录(查询的是多个表)
  222. public void GetDataSet2()
  223. {
  224. //创建连接对象
  225. SqlConnection conn = new SqlConnection(connString1);
  226. //sql 语句
  227. string sql = "select EmployeeName,Gender,NowAddress from Employee";
  228. //创建执行sql的对象
  229. SqlCommand cmd = new SqlCommand(sql, conn);
  230. //打开连接
  231. conn.Open();
  232. //创建数据适配器对象
  233. SqlDataAdapter da = new SqlDataAdapter(cmd);
  234. //创建一个数据集对象
  235. DataSet ds = new DataSet();
  236. //填充数据
  237. da.Fill(ds,"Employee");
  238. cmd.CommandText = "select DepartmentId,DepartmentName from Department";
  239. da.Fill(ds, "Department");
  240. //关闭连接
  241. conn.Close();
  242. //读取数据
  243. DataTable dt = ds.Tables["Employee"];
  244. foreach(DataRow dr in dt.Rows)
  245. {
  246. Console.WriteLine($"{dr["EmployeeName"]}\t{dr["Gender"]}\t{dr["NowAddress"]}");
  247. }
  248. Console.WriteLine("........................");
  249. foreach(DataRow dr in ds.Tables["Department"].Rows)
  250. {
  251. Console.WriteLine($"{dr["DepartmentId"]}\t{dr["DepartmentName"]}");
  252. }
  253. }
  254. //写带 参数的SQL 语句
  255. public void GetReaderList5()
  256. {
  257. //创建建立连接的对象 -- SqlConnection
  258. SqlConnection conn = new SqlConnection(connString1);
  259. //要执行的 sql 语句
  260. string sql = "select EmployeeName,Gender,NowAddress from Employee where EmployId > @Number";
  261. SqlParameter[] param = new SqlParameter[]
  262. {
  263. new SqlParameter("@Number",106)
  264. };
  265. //实例化 要执行 sql的对象 -- SqlCommand
  266. SqlCommand cmd = new SqlCommand(sql, conn);
  267. //添加参数
  268. cmd.Parameters.AddRange(param);
  269. //建立连接
  270. conn.Open();
  271. //执行结果集查询
  272. SqlDataReader reader = cmd.ExecuteReader();
  273. //逐行读取
  274. while (reader.Read())
  275. {
  276. string result = reader["EmployeeName"].ToString() + "\t" + reader[1] + "\t" + reader["NowAddress"];
  277. Console.WriteLine(result);
  278. }
  279. //关闭读取器
  280. reader.Close();
  281. //关闭连接
  282. conn.Close();
  283. }
  284. }
  285. }
复制代码
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace ConsoleApp1
  7. {
  8. internal class Program
  9. {
  10. static void Main(string[] args)
  11. {
  12. SqlServer sqlServer = new SqlServer();
  13. //建立连接,然后断开
  14. //sqlServer.ConnectDB();
  15. //插入新的行
  16. //sqlServer.Insert();
  17. //修改数据库中的信息
  18. //sqlServer.Update();
  19. //删除数据库中的记录
  20. //sqlServer.Delete();
  21. //执行只返回一个结果的 sql 语句
  22. //sqlServer.GetSingleResult();
  23. //执行只返回一个结果的 sql 语句
  24. //sqlServer.GetSingleResult2();
  25. //用 ExecuteScalar 来执行 插入操作,返回看新增的记录是第几条的
  26. //sqlServer.GetSingleResult3();
  27. //读取多条记录
  28. //sqlServer.GetReaderList();
  29. //读取多个表的多条记录
  30. //sqlServer.GetReaderList2();
  31. //使用 SqlDataAdapter 和 DataSet 读取数据
  32. //sqlServer.GetDataSet1();
  33. //使用 SqlDataAdapter 和 DataSet 读取多个表的数据
  34. //sqlServer.GetDataSet2();
  35. //使用带参的sql语句
  36. sqlServer.GetReaderList5();
  37. Console.ReadLine();
  38. }
  39. }
  40. }
复制代码

查询


通过关闭 SqlDataReader,来关闭 SqlConnection

七、SqlHelper

先安装库:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Configuration;
  7. using System.Web;
  8. //using System.Data.SqlClient;
  9. using System.Data;
  10. using Microsoft.SqlServer.Server;
  11. using Microsoft.Data.SqlClient;
  12. using System.Configuration;
  13. namespace ToolsLib
  14. {
  15. public class SqlServerHelper
  16. {
  17. //用于连接数据库的字符串
  18. //private static string ConnString { get; set; } = ConfigurationManager.ConnectionStrings["connString1"].ToString();
  19. private static string ConnString { get; set; } = ConfigurationManager.AppSettings["connString1"];
  20. /// <summary>
  21. /// 执行 insert\update\delete 类型的 sql 语句
  22. /// </summary>
  23. /// <param name="cmdText">sql语句或存储过程名称</param>
  24. /// <param name="paramArray">参数数组</param>
  25. /// <returns>受影响的行数</returns>
  26. /// <exception cref="Exception"></exception>
  27. public static int ExecuteNonQuery(string cmdText, SqlParameter[] paramArray = null)
  28. {
  29. SqlConnection conn = new SqlConnection(ConnString);
  30. SqlCommand cmd = new SqlCommand(cmdText, conn);
  31. if (paramArray != null)
  32. {
  33. cmd.Parameters.AddRange(paramArray);
  34. }
  35. try
  36. {
  37. conn.Open();
  38. return cmd.ExecuteNonQuery();//执行
  39. }
  40. catch (Exception ex)
  41. {
  42. //可以在这个地方写入日志(log文件)
  43. string errorMsg = $"{DateTime.Now}:执行public static int ExecuteNonQuery(sting cmdText,SqlParameter[]para---{ex.Message}";
  44. throw new Exception(errorMsg);
  45. }
  46. finally
  47. {
  48. conn.Close();
  49. }
  50. }
  51. /// <summary>
  52. /// 执行查询语句,查询结果是但是一个结果
  53. /// </summary>
  54. /// <param name="cmdText"></param>
  55. /// <param name="paramArray"></param>
  56. /// <returns></returns>
  57. /// <exception cref="Exception"></exception>
  58. public static object ExecuteScalar(string cmdText, SqlParameter[] paramArray = null)
  59. {
  60. SqlConnection conn = new SqlConnection(ConnString);
  61. SqlCommand cmd = new SqlCommand(cmdText, conn);
  62. if (paramArray != null)
  63. {
  64. cmd.Parameters.AddRange(paramArray);
  65. }
  66. try
  67. {
  68. conn.Open();
  69. return cmd.ExecuteScalar();
  70. }
  71. catch (Exception ex)
  72. {
  73. throw new Exception("执行public staticobjectExecute Scalar(string cmdText,SqlParameter[] paramArray = null)异常" + ex.Message);
  74. }
  75. finally
  76. {
  77. conn.Close();//关闭连接
  78. }
  79. }
  80. /// <summary>
  81. /// 执行查询语句
  82. /// </summary>
  83. /// <param name="cmdText"></param>
  84. /// <param name="paramArray"></param>
  85. /// <returns></returns>
  86. /// <exception cref="Exception"></exception>
  87. public static SqlDataReader ExecuteReader(string cmdText, SqlParameter[] paramArray = null)
  88. {
  89. SqlConnection conn = new SqlConnection(ConnString);
  90. SqlCommand cmd = new SqlCommand(cmdText, conn);
  91. if (paramArray != null)
  92. {
  93. cmd.Parameters.AddRange(paramArray);
  94. }
  95. try
  96. {
  97. conn.Open();
  98. //这里返回的 SqlDataReader 是用来进行进一步查询的,
  99. //这里的 加的入参是:CommandBehavior.CloseConnection 为了,关闭 SqlDataReader后来自动关闭 conn连接 做设置
  100. //因为 SqlDataReader 是需要在外部进行访问的
  101. return cmd.ExecuteReader(CommandBehavior.CloseConnection);//执行
  102. }
  103. catch (Exception ex)
  104. {
  105. throw new Exception($"执行public staticobjectExecute Scalar(stringcmdText,SqlParameter[] paramArray=null) ---{ex.Message}");
  106. }
  107. }
  108. /// <summary>
  109. /// 返回包含一张数据表的数据集的查询
  110. /// </summary>
  111. /// <param name="sql"></param>
  112. /// <param name="tableName"></param>
  113. /// <returns></returns>
  114. /// <exception cref="Exception"></exception>
  115. public static DataSet GetDataSet(string sql, string tableName = null)
  116. {
  117. SqlConnection conn = new SqlConnection(ConnString);
  118. SqlCommand cmd = new SqlCommand(sql, conn);
  119. SqlDataAdapter da = new SqlDataAdapter(cmd);
  120. DataSet ds = new DataSet();
  121. try
  122. {
  123. conn.Open();
  124. if (tableName == null)
  125. {
  126. da.Fill(ds);
  127. }
  128. else
  129. {
  130. da.Fill(ds, tableName);
  131. }
  132. return ds;
  133. }
  134. catch (Exception ex)
  135. {
  136. throw new Exception($"执行public static DataSet GetDataSet(string sql,string tableName=null)方法出现异常{ex.Message}");
  137. }
  138. finally
  139. {
  140. conn.Close();
  141. }
  142. }
  143. public static DataSet GetDataSet(Dictionary<string, string> dicTableAndSql)
  144. {
  145. SqlConnection conn = new SqlConnection(ConnString);
  146. SqlCommand cmd = new SqlCommand();
  147. cmd.Connection = conn;
  148. SqlDataAdapter da = new SqlDataAdapter(cmd);
  149. DataSet ds = new DataSet();
  150. try
  151. {
  152. conn.Open();
  153. foreach (string tbName in dicTableAndSql.Keys)
  154. {
  155. cmd.CommandText = dicTableAndSql[tbName];
  156. da.Fill(ds, tbName);//加入多个表
  157. }
  158. return ds;
  159. }
  160. catch (Exception ex)
  161. {
  162. throw new Exception("执行public static DataSet GetDataSet(string ssql,string tableName=null)方法出行异常" + ex.Message);
  163. }
  164. finally
  165. {
  166. conn.Close();
  167. }
  168. }
  169. }
  170. }
复制代码

八、存储过程的写法:

创建

  1. SET ANSI_NULLS ON
  2. GO
  3. SET QUOTED_IDENTIFIER ON
  4. GO
  5. CREATE PROCEDURE TestProcedure
  6. @Parameter1 Int =0,
  7. @Parameter2 Int output
  8. AS
  9. BEGIN
  10. SET NOCOUNT ON
  11. select * from UserT;
  12. Set @Parameter2 = 999;
  13. END
  14. GO
复制代码

修改

  1. USE [MyDB]
  2. GO
  3. /****** Object: StoredProcedure [dbo].[TestProcedure] Script Date: 12/17/2024 10:08:29 AM ******/
  4. -- 与null比较的结果会被视为 未知,而不是 true 或 false
  5. SET ANSI_NULLS ON
  6. GO
  7. -- 可以使用用双引号,引起来的关键字
  8. SET QUOTED_IDENTIFIER ON
  9. GO
  10. ALTER PROCEDURE [dbo].[TestProcedure]
  11. -- 输入参数
  12. @Parameter1 Int =0,
  13. -- 输出参数
  14. @Parameter2 Int output
  15. AS
  16. BEGIN
  17. -- 为了不返回 每条sql 影响多少条记录的信息
  18. SET NOCOUNT ON
  19. select * from UserT;
  20. Set @Parameter2 = 999;
  21. END
复制代码

执行

  1. declare @Parameter2 int;
  2. exec TestProcedure @Parameter1=20, @Parameter2= @Parameter2 output;
  3. select @Parameter2 as Parameter2;
复制代码

3、NModbus4 通讯库的使用

1、使用串口,封装 NModbus4 库

安装 NModbus4 库:

封装的代码:

  1. using Modbus.Device;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO.Ports;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace WindowsFormsApp1
  9. {
  10. /// <summary>
  11. /// 基于NModbus4的开源库的二次封装
  12. /// </summary>
  13. internal class ModbusRTU
  14. {
  15. #region 串口打开
  16. //声明.NET串口对象
  17. private SerialPort serialPort;
  18. //声明Modbus协议串口主设备对象
  19. private ModbusSerialMaster master;
  20. // COM1 9600 N 8 1
  21. public bool Connect(string portName, int baudRate,Parity parity,int dataBits,StopBits stopBits)
  22. {
  23. if(this.serialPort == null && this.serialPort.IsOpen)
  24. {
  25. this.serialPort.Close();
  26. }
  27. try
  28. {
  29. //创建.NET串口对象
  30. this.serialPort = new SerialPort(portName,baudRate, parity,dataBits,stopBits);
  31. //设置串口的读写超时时间(防止长时间阻塞)
  32. this.serialPort.ReadTimeout = 1000;
  33. this.serialPort.WriteTimeout = 1000;
  34. //打开 .NET 串口
  35. this.serialPort.Open();
  36. //使用 Modbus串口工厂方法 创建 Modbus串口主设备 对象
  37. master = ModbusSerialMaster.CreateRtu(this.serialPort);
  38. return true;
  39. }
  40. catch(Exception ex)
  41. {
  42. //打印异常信息
  43. throw new Exception("[串口]打开失败,"+ex.Message);
  44. }
  45. }
  46. #endregion
  47. #region 关闭串口
  48. public void DisConnect()
  49. {
  50. if(this.serialPort != null && this.serialPort.IsOpen)
  51. {
  52. //this.serialPort?.Close();
  53. this.serialPort.Close();
  54. }
  55. master = null;
  56. }
  57. #endregion
  58. #region 读取数据
  59. /// <summary>
  60. /// 【01】功能码:读取输出线圈
  61. /// </summary>
  62. /// <param name="slaveId">从站地址</param>
  63. /// <param name="start">起始线圈地址</param>
  64. /// <param name="length">线圈的数量</param>
  65. /// <returns>返回bool数组</returns>
  66. /// <exception cref="Exception"></exception>
  67. public bool[]ReadOutputCoils(byte slaveId,ushort start,ushort length)
  68. {
  69. try
  70. {
  71. //Coils 线圈的意思
  72. return this.master.ReadCoils(slaveId, start, length);
  73. }
  74. catch(Exception ex)
  75. {
  76. throw new Exception("[读取输出线程]失败" + ex.Message);
  77. }
  78. }
  79. /// <summary>
  80. /// [02] 功能码:读取输入线圈
  81. /// </summary>
  82. /// <param name="slaveId">从站地址</param>
  83. /// <param name="start">起始线圈地址</param>
  84. /// <param name="length">线圈的数量</param>
  85. /// <returns>返回bool数组</returns>
  86. /// <exception cref="Exception"></exception>
  87. public bool[] ReadInputCoils(byte slaveId, ushort start, ushort length)
  88. {
  89. try
  90. {
  91. return this.master.ReadInputs(slaveId, start, length);
  92. }
  93. catch (Exception ex)
  94. {
  95. throw new Exception("[读取输入线圈]失败:" + ex.Message);
  96. }
  97. }
  98. // 一个寄存器是两个 字节的大小
  99. /// <summary>
  100. /// 【03】 功能码:读取输出寄存器
  101. /// </summary>
  102. /// <param name="slaveId">从站地址</param>
  103. /// <param name="start">起始寄存器地址</param>
  104. /// <param name="length">寄存器的数量</param>
  105. /// <returns>返回byte数组</returns>
  106. /// <exception cref="Exception"></exception>
  107. public byte[] ReadHoldingRegister(byte slaveId,ushort start,ushort length)
  108. {
  109. try
  110. {
  111. //获取数据数组
  112. ushort[] data = this.master.ReadHoldingRegisters(slaveId, start, length);
  113. // 一个寄存器是两个 字节的大小
  114. //把ushort类型数组,转换成List字节数组
  115. List<byte> result = new List<byte>();
  116. foreach(var item in data)
  117. {
  118. result.AddRange(BitConverter.GetBytes(item));
  119. }
  120. return result.ToArray();
  121. }
  122. catch(Exception ex)
  123. {
  124. throw new Exception("[读取输出寄存器]失败," + ex.Message);
  125. }
  126. }
  127. /// <summary>
  128. /// [04] 功能码:读取输入寄存器
  129. /// </summary>
  130. /// <param name="slaveId">从站地址</param>
  131. /// <param name="start">起始寄存器地址</param>
  132. /// <param name="length">寄存器的数量</param>
  133. /// <returns>返回byte数组</returns>
  134. /// <exception cref="Exception"></exception>
  135. public byte[] ReadInputRegister(byte slaveId,ushort start,ushort length)
  136. {
  137. try
  138. {
  139. //获取数据数组
  140. ushort[] data = this.master.ReadInputRegisters(slaveId, start, length);
  141. //把ushort类型的数组,转换成List字节数组
  142. List<byte> result = new List<byte>();
  143. foreach (var item in data)
  144. {
  145. result.AddRange(BitConverter.GetBytes(item));
  146. }
  147. return result.ToArray();
  148. }
  149. catch(Exception ex)
  150. {
  151. throw new Exception("[读取输入寄存器]失败" + ex.Message);
  152. }
  153. }
  154. #endregion
  155. #region 写入数据
  156. /// <summary>
  157. /// [05] 功能码:预置单线圈
  158. /// </summary>
  159. /// <param name="slaveId">从站地址</param>
  160. /// <param name="start">当前线圈地址</param>
  161. /// <param name="value">线圈的值</param>
  162. /// <returns></returns>
  163. /// <exception cref="Exception"></exception>
  164. public bool PreSetSingleCoil(byte slaveId,ushort start,bool value)
  165. {
  166. try
  167. {
  168. this.master.WriteSingleCoil(slaveId, start, value);
  169. return true;
  170. }
  171. catch(Exception ex)
  172. {
  173. throw new Exception("[预置单线圈]失败," + ex.Message);
  174. }
  175. }
  176. /// <summary>
  177. /// [06]功能码:预置单寄存器
  178. /// </summary>
  179. /// <param name="slaveId">从站地址</param>
  180. /// <param name="address">寄存器地址</param>
  181. /// <param name="value">字节地址(2个字节)</param>
  182. /// <returns></returns>
  183. /// <exception cref="Exception"></exception>
  184. public bool PreSetSingleRegister(byte slaveId,ushort address,byte[] value)
  185. {
  186. try
  187. {
  188. this.master.WriteSingleRegister(slaveId, address, BitConverter.ToUInt16(value, 0));
  189. return true;
  190. }
  191. catch (Exception ex)
  192. {
  193. throw new Exception("【预置单寄存器】失败," + ex.Message);
  194. }
  195. }
  196. public bool PreSetSingleRegister(byte slaveId,ushort address,short value)
  197. {
  198. return PreSetSingleRegister(slaveId, address, BitConverter.GetBytes(value));
  199. }
  200. public bool PreSetSingleRegister(byte slaveId,ushort address,ushort value)
  201. {
  202. return PreSetSingleRegister(slaveId, address, BitConverter.GetBytes(value));
  203. }
  204. /// <summary>
  205. /// 【0F】 功能码 预置多个线圈
  206. /// </summary>
  207. /// <param name="slaveId">从站地址</param>
  208. /// <param name="start">线圈开始地址</param>
  209. /// <param name="value">布尔数组</param>
  210. /// <returns></returns>
  211. /// <exception cref="Exception"></exception>
  212. public bool PreSetMutiCoils(byte slaveId,ushort start,bool[] value)
  213. {
  214. try
  215. {
  216. this.master.WriteMultipleCoils(slaveId, start, value);
  217. return true;
  218. }
  219. catch(Exception ex){
  220. throw new Exception("[预制多线圈]失败," + ex.Message);
  221. }
  222. }
  223. /// <summary>
  224. /// [10] 功能码:预制多个寄存器
  225. /// </summary>
  226. /// <param name="slaveId">从站地址</param>
  227. /// <param name="start">寄存器开始地址</param>
  228. /// <param name="values">字节数组</param>
  229. /// <returns></returns>
  230. /// <exception cref="Exception"></exception>
  231. public bool PreSetMultiRegister(byte slaveId,ushort start, byte[] values)
  232. {
  233. //必须是偶数字节
  234. // 因为两字节 , 才是也给寄存器的大小
  235. if(values == null||values.Length == 0 || values.Length%2 == 1)
  236. {
  237. return false;
  238. }
  239. //将字节数组转换成ushort数组
  240. ushort[] data = new ushort[values.Length / 2];
  241. for (int i = 0; i < values.Length; i += 2)
  242. {
  243. data[i] = BitConverter.ToUInt16(values, i);
  244. }
  245. try
  246. {
  247. this.master.WriteMultipleRegisters(slaveId, start, data);
  248. return true;
  249. }
  250. catch(Exception ex)
  251. {
  252. throw new Exception("[预制多寄存器]失败,"+ex.Message);
  253. }
  254. }
  255. /// <summary>
  256. /// [0F] 功能码:预制多个线圈
  257. /// </summary>
  258. /// <param name="slaveId">站地址</param>
  259. /// <param name="start">线圈开始地址</param>
  260. /// <param name="value">布尔数组</param>
  261. /// <returns></returns>
  262. /// <exception cref="Exception"></exception>
  263. public bool PreSetMultiCoils(byte slaveId,ushort start,bool[] value)
  264. {
  265. try
  266. {
  267. this.master.WriteMultipleCoils(slaveId,start,value);
  268. return true;
  269. }
  270. catch (Exception ex)
  271. {
  272. throw new Exception("[预制多个线圈]失败" + ex.Message);
  273. }
  274. }
  275. #endregion
  276. }
  277. }
复制代码

三、手写通信库

四、WPF基本使用

0、xaml 的基础操作

xaml是一种声明型语言,一般来讲,一个标签就是一个对象;而一个标签的属性就是一个对象的属性。
给标签属性赋值有三种方式:

1、 Attribute = Value 形式

画一个 长方形

  1. <Rectangle Width="100" Height="80" Stroke="Black"/>
复制代码

画一个三角形

  1. <Path Data="M 0,0 L 200,100 L 100,200 Z" Stroke="Black" Fill="Red"/>
复制代码
将一个字符串转换成标签(对象)的写法:


MainWindow.xaml

  1. <Window x:Class="WpfApp1.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:WpfApp1"
  7. mc:Ignorable="d"
  8. Title="MainWindow" Height="450" Width="800">
  9. <Window.Resources>
  10. <local:Dog x:Key="dog1" Name="Bob1"/>
  11. <local:Dog x:Key="dog2" Name="Bob2"/>
  12. <local:Dog x:Key="dog3" Name="Bob3" Child="123"/>
  13. </Window.Resources>
  14. <Grid>
  15. <Button Content="Hello!" Width="120" Height="30" Click="Button_Click"/>
  16. </Grid>
  17. </Window>
复制代码

Dog.cs

  1. using System.ComponentModel;
  2. using System.Globalization;
  3. namespace WpfApp1
  4. {
  5. //为类添加转换规则
  6. [TypeConverterAttribute(typeof(NameToDogTypeConverter))]
  7. public class Dog
  8. {
  9. public string Name { get; set; }
  10. public Dog Child { get; set; }
  11. }
  12. public class NameToDogTypeConverter : TypeConverter
  13. {
  14. //将字符串转成 Dog 的规则
  15. public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
  16. {
  17. string name = value.ToString();
  18. Dog child = new Dog();
  19. child.Name = name;
  20. return child;
  21. }
  22. }
  23. }
复制代码

MainWindow.xaml.cs

  1. using System.Windows;
  2. namespace WpfApp1
  3. {
  4. /// <summary>
  5. /// MainWindow.xaml 的交互逻辑
  6. /// </summary>
  7. public partial class MainWindow : Window
  8. {
  9. public MainWindow()
  10. {
  11. InitializeComponent();
  12. }
  13. private void Button_Click(object sender, RoutedEventArgs e)
  14. {
  15. Dog dog =this.FindResource("dog3") as Dog; ;//找到字典资源中 标签对象的方法
  16. if(null != dog)
  17. {
  18. //取出标签对象中的属性
  19. MessageBox.Show(dog.Name + "/" + dog.Child.Name);
  20. }
  21. }
  22. }
  23. }
复制代码

另一种等价的添加属性 的方式:

  1. <Button Content="登录" FontSize="20" Height="50" Width="300"/>
复制代码
  1. <Button Content="登录">
  2. <Setter Property="Background" Value="Red"/>
  3. <Setter Property="FontSize" Value="20"/>
  4. <Setter Property="Height" Value="50"/>
  5. <Setter Property="Width" Value="300"/>
  6. </Button>
复制代码
2、属性标签

形如:

就是属性标签,它不是一个对象,而是对象的属性,用标签的形式来写
例子 1:

  1. <Window x:Class="WpfApp1.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. mc:Ignorable="d"
  7. Title="MainWindow" Height="450" Width="800">
  8. <Grid>
  9. <Rectangle Width="200" Height="160" Stroke="Blue">
  10. <Rectangle.Fill>
  11. <LinearGradientBrush>
  12. <LinearGradientBrush.StartPoint>
  13. <Point X="0" Y="0"/>
  14. </LinearGradientBrush.StartPoint>
  15. <LinearGradientBrush.EndPoint>
  16. <Point X="1" Y="1"/>
  17. </LinearGradientBrush.EndPoint>
  18. <LinearGradientBrush.GradientStops>
  19. <GradientStopCollection>
  20. <GradientStop Offset="0.2" Color="LightBlue"/>
  21. <GradientStop Offset="0.7" Color="DarkBlue"/>
  22. <GradientStop Offset="1.0" Color="Blue"/>
  23. </GradientStopCollection>
  24. </LinearGradientBrush.GradientStops>
  25. </LinearGradientBrush>
  26. </Rectangle.Fill>
  27. </Rectangle>
  28. </Grid>
  29. </Window>
复制代码

例子 2:

  1. <Window x:Class="WpfApp1.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. mc:Ignorable="d"
  7. Title="MainWindow" Height="450" Width="800">
  8. <Grid>
  9. <Button Width="120" Height="30">
  10. <Button.Content>
  11. <Rectangle Width="20" Height="20" Stroke="DarkGreen" Fill="LawnGreen"/>
  12. </Button.Content>
  13. </Button>
  14. </Grid>
  15. </Window>
复制代码
3、标签扩展

1、创建一个项目

程序入口:

默认入口点:WPF 应用程序的默认入口点是 App.xaml 和 App.xaml.cs 文件。在这些文件中定义了应用程序的启动逻辑和主窗口。
自定义入口点:如果需要,可以在代码中定义一个 Main 方法并在其中创建和运行 Application 对象,但这不是必需的,除非你有特定的初始化需求。

手写函数函数入口(一般不需要):

  1. // Entry point defined in a custom Main method (if needed)
  2. public static class Program
  3. {
  4. [STAThread]
  5. public static void Main()
  6. {
  7. var app = new App();
  8. app.InitializeComponent();
  9. app.Run();
  10. }
  11. }
复制代码
  1. // App.xaml.cs
  2. using System.Windows;
  3. namespace MyWpfApp
  4. {
  5. public partial class App : Application
  6. {
  7. // Application startup logic can be placed here
  8. protected override void OnStartup(StartupEventArgs e)
  9. {
  10. base.OnStartup(e);
  11. // Custom startup logic (if needed)
  12. }
  13. protected override void OnExit(ExitEventArgs e)
  14. {
  15. base.OnExit(e);
  16. // Custom exit logic (if needed)
  17. }
  18. }
  19. }
复制代码

窗体 xaml 文件的解读:

2、模拟一个文本编辑的界面(使用控件:Grid | StackPanel | Button | TextBox)

准备

button的属性: Width HorizontalAlignment VerticalAlignment Height

  1. <Grid>
  2. <Button Width="200" HorizontalAlignment="Left" VerticalAlignment="Top" Height="40"/>
  3. <Button Width="200" HorizontalAlignment="Center" VerticalAlignment="Top" Height="40"/>
  4. <Button Width="200" HorizontalAlignment="Right" VerticalAlignment="Top" Height="40"/>
  5. <Button Width="200" HorizontalAlignment="Left" VerticalAlignment="Center" Height="40"/>
  6. <Button Width="200" HorizontalAlignment="Center" VerticalAlignment="Center" Height="40"/>
  7. <Button Width="200" HorizontalAlignment="Right" VerticalAlignment="Center" Height="40"/>
  8. <Button Width="200" HorizontalAlignment="Left" VerticalAlignment="Bottom" Height="40"/>
  9. <Button Width="200" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="40"/>
  10. <Button Width="200" HorizontalAlignment="Right" VerticalAlignment="Bottom" Height="40"/>
  11. </Grid>
复制代码

Stackanel控件:
.

占用多列的写法:
Grid.ColumnSpan=“2”

  1. <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
  2. <Button Height="20" Width="70"/>
  3. <Button Height="20" Width="70"/>
  4. <Button Height="20" Width="70"/>
  5. </StackPanel>
复制代码

  1. <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
  2. <Button Height="20" Width="70"/>
  3. <Button Height="20" Width="70"/>
  4. <Button Height="20" Width="70"/>
  5. </StackPanel>
复制代码

Grid控件:

  1. <Grid ShowGridLines="True">
  2. <Grid.RowDefinitions>
  3. <RowDefinition Height="1*"/>
  4. <RowDefinition Height="1*"/>
  5. <RowDefinition Height="1*"/>
  6. <RowDefinition Height="1*"/>
  7. </Grid.RowDefinitions>
  8. <Grid.ColumnDefinitions>
  9. <ColumnDefinition Width="1*"/>
  10. <ColumnDefinition Width="1*"/>
  11. <ColumnDefinition Width="1*"/>
  12. <ColumnDefinition Width="1*"/>
  13. <ColumnDefinition Width="1*"/>
  14. </Grid.ColumnDefinitions>
  15. <Button Grid.Row="1" Grid.Column="1">1,1</Button>
  16. <Button Grid.Row="1" Grid.Column="2">1,2</Button>
  17. <Button Grid.Row="1" Grid.Column="3">1,3</Button>
  18. <Button Grid.Row="2" Grid.Column="1">2,1</Button>
  19. <Button Grid.Row="2" Grid.Column="2">2,2</Button>
  20. <Button Grid.Row="2" Grid.Column="3">2,3</Button>
  21. </Grid>
复制代码

Grid 的三种长度设置:
AUTO 安内容来
绝对宽高 每个单位是 1/96英寸
“1*” 按比例来

TextBox 文本编辑的控件

  1. <TextBox TextWrapping="Wrap"/>
复制代码

应用

  1. <Window x:Class="WpfApp1.EditWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:WpfApp1"
  7. mc:Ignorable="d"
  8. Title="EditWindow" Height="450" Width="800">
  9. <Grid>
  10. <Grid.RowDefinitions>
  11. <RowDefinition Height="20"/>
  12. <RowDefinition Height="20"/>
  13. <RowDefinition Height="1*"/>
  14. <RowDefinition Height="20"/>
  15. </Grid.RowDefinitions>
  16. <StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal">
  17. <Button Height="20" Width="70" Content="文件"/>
  18. <Button Height="20" Width="70" Content="编辑"/>
  19. <Button Height="20" Width="70" Content="查看"/>
  20. <Button Height="20" Width="70" Content="外观"/>
  21. <Button Height="20" Width="70" Content="设置"/>
  22. </StackPanel>
  23. <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
  24. <Button Height="20" Width="20" Content="1"/>
  25. <Button Height="20" Width="20" Content="2"/>
  26. <Button Height="20" Width="20" Content="3"/>
  27. <Button Height="20" Width="20" Content="4"/>
  28. <Button Height="20" Width="20" Content="5"/>
  29. </StackPanel>
  30. <Grid Grid.Row="2" Grid.Column="0">
  31. <Grid>
  32. <Grid.ColumnDefinitions>
  33. <ColumnDefinition Width="40"/>
  34. <ColumnDefinition/>
  35. </Grid.ColumnDefinitions>
  36. <StackPanel Grid.Column="0" Grid.Row="0">
  37. <Button Height="20" Content="1"/>
  38. <Button Height="20" Content="2"/>
  39. <Button Height="20" Content="3"/>
  40. <Button Height="20" Content="4"/>
  41. <Button Height="20" Content="5"/>
  42. <Button Height="20" Content="6"/>
  43. <Button Height="20" Content="7"/>
  44. <Button Height="20" Content="8"/>
  45. <Button Height="20" Content="9"/>
  46. <Button Height="20" Content="10"/>
  47. <Button Height="20" Content="11"/>
  48. <Button Height="20" Content="12"/>
  49. <Button Height="20" Content="13"/>
  50. <Button Height="20" Content="14"/>
  51. <Button Height="20" Content="15"/>
  52. <Button Height="20" Content="16"/>
  53. <Button Height="20" Content="17"/>
  54. </StackPanel>
  55. <TextBox Grid.Column="1" TextWrapping="Wrap"/>
  56. </Grid>
  57. </Grid>
  58. <Grid Grid.Row="3" Grid.Column="0">
  59. <Grid.ColumnDefinitions>
  60. <ColumnDefinition Width="auto"/>
  61. <ColumnDefinition Width="1*"/>
  62. <ColumnDefinition Width="1*"/>
  63. <ColumnDefinition Width="1*"/>
  64. <ColumnDefinition Width="1*"/>
  65. <ColumnDefinition Width="1*"/>
  66. <ColumnDefinition Width="1*"/>
  67. <ColumnDefinition Width="1*"/>
  68. </Grid.ColumnDefinitions>
  69. <Button Grid.Column="0">Normal text file</Button>
  70. <Button Grid.Column="1">Length:1,125</Button>
  71. <Button Grid.Column="2">lines:26</Button>
  72. <Button Grid.Column="3">Ln:6 Col:57 Sel:3</Button>
  73. <Button Grid.Column="4">1</Button>
  74. <Button Grid.Column="5">Windows(CR LF)</Button>
  75. <Button Grid.Column="6">UTF-8-BOM</Button>
  76. <Button Grid.Column="7">INS</Button>
  77. </Grid>
  78. </Grid>
  79. </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 文件内容,样式是会发生改变的

  1. <Window x:Class="WpfApp1.EditWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:WpfApp1"
  7. mc:Ignorable="d"
  8. Title="EditWindow" Height="450" Width="800">
  9. <Window.Resources>
  10. <Style TargetType="Button">
  11. <Setter Property="Background" Value="WhiteSmoke"/>
  12. <Setter Property="FontSize" Value="20"/>
  13. <Setter Property="Height" Value="50"/>
  14. <Setter Property="Width" Value="300"/>
  15. <Setter Property="Margin" Value="20,10"/>
  16. </Style>
  17. <Style x:Key="LoginStyle" TargetType="Button">
  18. <Setter Property="Background" Value="Green"/>
  19. <Setter Property="FontSize" Value="20"/>
  20. <Setter Property="Height" Value="50"/>
  21. <Setter Property="Width" Value="300"/>
  22. </Style>
  23. <Style x:Key="QuitStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button} }">
  24. <Setter Property="Background" Value="Red"/>
  25. </Style>
  26. </Window.Resources>
  27. <StackPanel>
  28. <Button Style="{StaticResource LoginStyle}" Content="登录"/>
  29. <Button Style="{DynamicResource QuitStyle}" Content="退出"/>
  30. <Button Content="忘记密码"/>
  31. </StackPanel>
  32. </Window>
复制代码

继承:

  1. <Window x:Class="WpfApp1.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="登录界面" Height="270" Width="500" ResizeMode="NoResize">
  5. <Window.Resources>
  6. <Style x:Key="baseButtonStyle" TargetType="Button">
  7. <Setter Property="FontSize" Value="30"/>
  8. <Setter Property="Foreground" Value="Blue"/>
  9. </Style>
  10. <Style x:Key="defaultButtonStyle" TargetType="Button" BasedOn="{StaticResource baseButtonStyle}">
  11. <Setter Property="Width" Value="100"/>
  12. <Setter Property="Height" Value="50"/>
  13. </Style>
  14. </Window.Resources>
  15. <Grid>
  16. <Button Style="{StaticResource defaultButtonStyle}" Content="ghyu"/>
  17. </Grid>
  18. </Window>
复制代码

4、添加资源字典

第一步:添加资源字典 xaml 文件


资源字典文件:Dictionary1.xaml

  1. <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  2. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  3. <Style TargetType="Button">
  4. <Setter Property="Background" Value="WhiteSmoke"/>
  5. <Setter Property="FontSize" Value="20"/>
  6. <Setter Property="Height" Value="50"/>
  7. <Setter Property="Width" Value="300"/>
  8. <Setter Property="Margin" Value="20,10"/>
  9. </Style>
  10. <Style x:Key="LoginStyle" TargetType="Button">
  11. <Setter Property="Background" Value="Green"/>
  12. <Setter Property="FontSize" Value="20"/>
  13. <Setter Property="Height" Value="50"/>
  14. <Setter Property="Width" Value="300"/>
  15. </Style>
  16. <Style x:Key="QuitStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button} }">
  17. <Setter Property="Background" Value="Red"/>
  18. </Style>
  19. </ResourceDictionary>
复制代码

第二步:在 app.xml 文件中引入 资源字典文件

  1. <ResourceDictionary Source="/WpfApp1;component/Dictionary1.xaml"/>
  2. 这里的 WpfApp1 是 命名空间
  3. Dictionary1.xaml 是 要加载的文件名
复制代码
  1. <Application x:Class="WpfApp1.App"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:local="clr-namespace:WpfApp1"
  5. StartupUri="EditWindow.xaml">
  6. <Application.Resources>
  7. <ResourceDictionary>
  8. <ResourceDictionary.MergedDictionaries>
  9. <ResourceDictionary Source="/WpfApp1;component/Dictionary1.xaml"/>
  10. </ResourceDictionary.MergedDictionaries>
  11. </ResourceDictionary>
  12. </Application.Resources>
  13. </Application>
复制代码

第三步:在标签中,可以直接调用

  1. <Window x:Class="WpfApp1.EditWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:WpfApp1"
  7. mc:Ignorable="d"
  8. Title="EditWindow" Height="450" Width="800">
  9. <StackPanel>
  10. <Button Style="{StaticResource LoginStyle}" Content="登录"/>
  11. <Button Style="{DynamicResource QuitStyle}" Content="退出"/>
  12. <Button Content="忘记密码"/>
  13. </StackPanel>
  14. </Window>
复制代码

5、用模板自定义一个带圆角的 Button 控件 及 触发器 的写法

  1. <ControlTemplate TargetType="Button">
复制代码

里 TargetType=“Button” 和 TargetTye=“{x:Type Button}” 是一样的

  1. <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="6">
复制代码

在这一行中,{TemplateBinding Background}" 表示从原 button 标签中去取 叫 Background 的属性

  1. <Window x:Class="WpfApp1.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:WpfApp1"
  7. mc:Ignorable="d"
  8. Title="123" Height="450" Width="800">
  9. <Grid>
  10. <Button Content="btn" Background="Red" BorderBrush="Black" FontSize="20" Width="200" Height="30" BorderThickness="3">
  11. <Button.Template>
  12. <ControlTemplate TargetType="Button">
  13. <Border x:Name="boder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="6">
  14. <TextBlock Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
  15. </Border>
  16. <ControlTemplate.Triggers>
  17. <Trigger Property="IsMouseOver" Value="True">
  18. <Setter TargetName="boder" Property="Background" Value="Black"/>
  19. </Trigger>
  20. <Trigger Property="IsPressed" Value="True">
  21. <Setter TargetName="boder" Property="Background" Value="WhiteSmoke"/>
  22. </Trigger>
  23. </ControlTemplate.Triggers>
  24. </ControlTemplate>
  25. </Button.Template>
  26. </Button>
  27. </Grid>
  28. </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、触发器 的另一些实践

  1. <Window x:Class="WpfApp1.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="登录界面" Height="270" Width="500">
  5. <Window.Resources>
  6. <Style x:Key="defaultButtonStyle" TargetType="Button">
  7. <Setter Property="Width" Value="100"/>
  8. <Setter Property="Height" Value="30"/>
  9. <Style.Triggers>
  10. <Trigger Property="IsMouseOver" Value="True">
  11. <Setter Property="Foreground" Value="Red"/>
  12. <Setter Property="FontSize" Value="30"/>
  13. </Trigger>
  14. <Trigger Property="IsMouseOver" Value="False">
  15. <Setter Property="Foreground" Value="Blue"/>
  16. <Setter Property="FontSize" Value="20"/>
  17. </Trigger>
  18. </Style.Triggers>
  19. </Style>
  20. <Style x:Key="defaultButtonStyle2" TargetType="Button">
  21. <Setter Property="Width" Value="100"/>
  22. <Setter Property="Height" Value="30"/>
  23. <Style.Triggers>
  24. <MultiTrigger>
  25. <MultiTrigger.Conditions>
  26. <Condition Property="IsMouseOver" Value="true"/>
  27. <Condition Property="IsFocused" Value="True"/>
  28. </MultiTrigger.Conditions>
  29. <MultiTrigger.Setters>
  30. <Setter Property="Foreground" Value="Red"/>
  31. </MultiTrigger.Setters>
  32. </MultiTrigger>
  33. </Style.Triggers>
  34. </Style>
  35. <Style x:Key="defaultButtonStyle3" TargetType="Button">
  36. <Setter Property="Width" Value="100"/>
  37. <Setter Property="Height" Value="30"/>
  38. <Style.Triggers>
  39. <EventTrigger RoutedEvent="Mouse.MouseEnter">
  40. <EventTrigger.Actions>
  41. <BeginStoryboard>
  42. <Storyboard>
  43. <DoubleAnimation Duration="0:0:0.2"
  44. Storyboard.TargetProperty="FontSize"
  45. To="30">
  46. </DoubleAnimation>
  47. </Storyboard>
  48. </BeginStoryboard>
  49. </EventTrigger.Actions>
  50. </EventTrigger>
  51. </Style.Triggers>
  52. </Style>
  53. </Window.Resources>
  54. <StackPanel>
  55. <Button Style="{StaticResource defaultButtonStyle}" Content="Hello"/>
  56. <Button Style="{StaticResource defaultButtonStyle2}" Content="Hello"/>
  57. <Button Style="{StaticResource defaultButtonStyle3}" Content="Hello"/>
  58. </StackPanel>
  59. </Window>
复制代码

5-3、生成模板副本:


将 模板放在 资源字典中:

5-4、控件模板

5-5、数据模板

第一个例子:



第二个例子:

6、 button 的 和 点击事件 的写法:

6-2、添加点击事件的两种方式:

1 直接在 xaml 代码中进行添加
2 根据名字找到控件的 点击事件,在 cs 代码中添加

  1. <Window x:Class="WpfApp1.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:sys="clr-namespace:System;assembly=mscorlib"
  7. Title="MainWindow" Height="450" Width="800">
  8. <Window.Resources>
  9. <sys:String x:Key="stringHello">Hello WPF!</sys:String>
  10. </Window.Resources>
  11. <Grid>
  12. <TextBlock Height="24" Width="120" Background="LightBlue"
  13. Text="{StaticResource ResourceKey=stringHello}"/>
  14. </Grid>
  15. </Window>
复制代码

7-1、控件间的属性绑定

  1. <Grid>
  2. <StackPanel>
  3. <Slider x:Name="slider" Margin="5"/>
  4. <TextBox
  5. Height="30"
  6. Margin="5"
  7. Text="{Binding ElementName=slider, Path=Value, Mode=OneTime}"/>
  8. <!--只进行一次绑定-->
  9. <TextBox
  10. Height="30"
  11. Margin="5"
  12. Text="{Binding ElementName=slider, Path=Value, Mode=OneWay}"/>
  13. <!--单向绑定-->
  14. <TextBox
  15. Height="30"
  16. Margin="5"
  17. Text="{Binding ElementName=slider, Path=Value}"/>
  18. <!--默认是双向绑定-->
  19. </StackPanel>
  20. </Grid>
复制代码

7-2、一个简单的数据绑定的写法(属性的变更通知)

完成前 3 步,可以实现 数据从界面 向 代码的传递
完成后 2 步,可以实现 界面 向 代码层的数据传递

代码:

  1. <Window x:Class="WpfApp1.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:WpfApp1"
  7. mc:Ignorable="d"
  8. Title="登录界面" Height="270" Width="500" ResizeMode="NoResize">
  9. <Grid>
  10. <Grid.RowDefinitions>
  11. <RowDefinition Height="15"/>
  12. <RowDefinition Height="30"/>
  13. <RowDefinition Height="auto"/>
  14. <RowDefinition Height="5*"/>
  15. </Grid.RowDefinitions>
  16. <TextBox Grid.Row="1" Text="X6337TEB6----登录系统" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
  17. <Grid Grid.Row="2">
  18. <Grid.RowDefinitions>
  19. <RowDefinition Height="20"/>
  20. <RowDefinition Height="20"/>
  21. <RowDefinition Height="20"/>
  22. <RowDefinition Height="27"/>
  23. </Grid.RowDefinitions>
  24. <Grid.ColumnDefinitions>
  25. <ColumnDefinition Width="1*"/>
  26. <ColumnDefinition Width="auto"/>
  27. <ColumnDefinition Width="150"/>
  28. <ColumnDefinition Width="1*"/>
  29. </Grid.ColumnDefinitions>
  30. <TextBlock Grid.Row="0" Grid.Column="1" Text="用户名"/>
  31. <TextBox Text ="{Binding UserName}" Grid.Row="0" Grid.Column="2" Margin="3,2"/>
  32. <TextBlock Grid.Row="1" Grid.Column="1" Text="密码"/>
  33. <TextBox Text="{Binding PassWord}" Grid.Row="1" Grid.Column="2" Margin="3,2"/>
  34. <CheckBox Grid.ColumnSpan="2" Grid.Row="2" Grid.Column="1" Content="记住密码"/>
  35. <Button Grid.ColumnSpan="2" Grid.Row="3" Grid.Column="1" Content="登录" Margin="3,1" Click="Button_Click"/>
  36. </Grid>
  37. </Grid>
  38. </Window>
复制代码
  1. using System;
  2. using System.ComponentModel;
  3. using System.Windows;
  4. namespace WpfApp1
  5. {
  6. /// <summary>
  7. /// MainWindow.xaml 的交互逻辑
  8. /// </summary>
  9. public partial class MainWindow : Window,INotifyPropertyChanged
  10. {
  11. #region 数据绑定的固定写法
  12. private string _userName;
  13. private string _passWord;
  14. public string UserName {
  15. get { return _userName; }
  16. set
  17. {
  18. _userName = value;
  19. RaisePropertyChanged("UserName");
  20. }
  21. }
  22. public string PassWord
  23. {
  24. get { return _passWord; }
  25. set
  26. {
  27. _passWord = value;
  28. RaisePropertyChanged("PassWord");
  29. }
  30. }
  31. public event PropertyChangedEventHandler PropertyChanged;
  32. private void RaisePropertyChanged(string propertyName)
  33. {
  34. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  35. }
  36. #endregion
  37. public MainWindow()
  38. {
  39. InitializeComponent();
  40. this.DataContext = this;
  41. }
  42. /// <summary>
  43. /// 登录按钮
  44. /// </summary>
  45. /// <param name="sender"></param>
  46. /// <param name="e"></param>
  47. private void Button_Click(object sender, RoutedEventArgs e)
  48. {
  49. Console.WriteLine($"{UserName}-{PassWord}");
  50. UserName = "Admin";
  51. PassWord = "123";
  52. }
  53. }
  54. }
复制代码

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

  1. <Button Grid.Row="0" Command="{Binding ClickBtn}" Tag="a" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Tag}">a</Button>
复制代码
  1. public ICommand ClickBtn
  2. {
  3. get
  4. {
  5. return new ExecuteCommond((param) =>
  6. {
  7. // param 是 CommandParameter 传递的值
  8. string tag = param as string;
  9. Console.WriteLine($"Tag: {tag}");
  10. });
  11. }
  12. }
复制代码

传入控件自身

  1. <Button Grid.Row="0" Command="{Binding ClickBtn}" Tag="a" CommandParameter="{Binding RelativeSource={RelativeSource Self}}">a</Button>
复制代码
  1. public ICommand ClickBtn
  2. {
  3. get
  4. {
  5. return new ExecuteCommond((param) =>
  6. {
  7. if (param is Button button)
  8. {
  9. var tag = button.Tag; // 获取按钮的Tag属性
  10. Console.WriteLine($"Tag: {tag}");
  11. }
  12. });
  13. }
  14. }
复制代码

多种入参的 ICommand 的实现

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows.Input;
  7. namespace QIPWaterDeal.ViewModel
  8. {
  9. public class ExecuteCommond : ICommand
  10. {
  11. /// <summary>
  12. /// 判断命令是否可以执行
  13. /// </summary>
  14. private readonly Func<bool> _canExecute;
  15. /// <summary>
  16. /// 执行无参数的操作
  17. /// </summary>
  18. private readonly Action _execute;
  19. /// <summary>
  20. /// 执行带参数的操作
  21. /// </summary>
  22. private readonly Action<object> _executeWithParameter;
  23. /// <summary>
  24. /// 构造方法(无参数版本)
  25. /// </summary>
  26. public ExecuteCommond(Action execute, Func<bool> canExecute = null)
  27. {
  28. _execute = execute;
  29. _canExecute = canExecute;
  30. }
  31. /// <summary>
  32. /// 构造方法(带参数版本)
  33. /// </summary>
  34. public ExecuteCommond(Action<object> executeWithParameter, Func<bool> canExecute = null)
  35. {
  36. _executeWithParameter = executeWithParameter;
  37. _canExecute = canExecute;
  38. }
  39. public event EventHandler CanExecuteChanged;
  40. /// <summary>
  41. /// 是否可以执行命令
  42. /// </summary>
  43. public bool CanExecute(object parameter)
  44. {
  45. return _canExecute == null || _canExecute();
  46. }
  47. /// <summary>
  48. /// 执行命令
  49. /// </summary>
  50. public void Execute(object parameter)
  51. {
  52. if (_execute != null)
  53. {
  54. _execute.Invoke();
  55. }
  56. else if (_executeWithParameter != null)
  57. {
  58. _executeWithParameter.Invoke(parameter);
  59. }
  60. }
  61. /// <summary>
  62. /// 通知CanExecute状态发生变化
  63. /// </summary>
  64. public void RaiseCanExecuteChanged()
  65. {
  66. CanExecuteChanged?.Invoke(this, EventArgs.Empty);
  67. }
  68. }
  69. }
复制代码

8-2 MVVM的另一种实践(对 进行包装)

一个实际的例子


MainWindow.xml

  1. <Window x:Class="WpfApp1.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="登录界面" Height="270" Width="500" ResizeMode="NoResize">
  5. <Grid>
  6. <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
  7. <TextBox x:Name="input1" Width="100" Height="24" Margin="3" Text="{Binding Input1}"></TextBox>
  8. <TextBox x:Name="input2" Width="100" Height="24" Margin="3" Text="{Binding Input2}"></TextBox>
  9. <TextBox x:Name="input3" Width="100" Height="24" Margin="3" Text="{Binding Input3}"></TextBox>
  10. <Button x:Name="btn1" Width="100" Height="24" Margin="3" Content="Add" Command="{Binding AddCommand}"></Button>
  11. </StackPanel>
  12. </Grid>
  13. </Window>
复制代码

NotificationObject

  1. using System.ComponentModel;
  2. namespace WpfApp1
  3. {
  4. /// <summary>
  5. /// VM 的基类
  6. /// </summary>
  7. public class NotificationObject:INotifyPropertyChanged
  8. {
  9. public event PropertyChangedEventHandler PropertyChanged;
  10. public void RaisePropertyChange(string propertyName)
  11. {
  12. if(this.PropertyChanged != null)
  13. {
  14. this.PropertyChanged.Invoke(this,new PropertyChangedEventArgs(propertyName));
  15. }
  16. }
  17. }
  18. }
复制代码

DelegateCommand

  1. using System;
  2. using System.Windows.Input;
  3. namespace WpfApp1
  4. {
  5. public class DelegateCommand:ICommand
  6. {
  7. public bool CanExecute(object parameter)
  8. {
  9. if(this.CanExecuteFunc == null)
  10. {
  11. return true;
  12. }
  13. return this.CanExecuteFunc(parameter);
  14. }
  15. public event EventHandler CanExecuteChanged;
  16. public void Execute(object parameter)
  17. {
  18. if(this.ExecuteAction == null)
  19. {
  20. return;
  21. }
  22. this.ExecuteAction(parameter);
  23. }
  24. public Action<object> ExecuteAction { get; set; }
  25. public Func<object,bool> CanExecuteFunc { get; set; }
  26. }
  27. }
复制代码

MainWindowViewModel

  1. using System;
  2. namespace WpfApp1
  3. {
  4. internal class MainWindowViewModel : NotificationObject
  5. {
  6. #region 数据属性
  7. private double input1;
  8. public double Input1
  9. {
  10. get
  11. {
  12. return input1;
  13. }
  14. set
  15. {
  16. input1 = value;
  17. this.RaisePropertyChange(nameof(Input1));
  18. }
  19. }
  20. private double input2;
  21. public double Input2
  22. {
  23. get
  24. {
  25. return input2;
  26. }
  27. set
  28. {
  29. input2 = value;
  30. this.RaisePropertyChange(nameof(Input2));
  31. }
  32. }
  33. private double input3;
  34. public double Input3 {
  35. get {
  36. return input3;
  37. }
  38. set {
  39. input3 = value;
  40. this.RaisePropertyChange(nameof(Input3));
  41. }
  42. }
  43. #endregion
  44. #region 命令属性
  45. public DelegateCommand AddCommand { get; set; }
  46. private void Add(object parameter)
  47. {
  48. this.Input3 = this.Input1 + this.Input2;
  49. }
  50. public MainWindowViewModel()
  51. {
  52. this.AddCommand = new DelegateCommand();
  53. this.AddCommand.ExecuteAction = new Action<object>(this.Add);
  54. }
  55. #endregion
  56. }
  57. }
复制代码

8-3、利用 特性(反射),优化数据变更通知(接口)的写法

9、写一个自定义控件(添加 自定义 依赖属性)


字典资源

加入字典资源

继承 Button 的自定义控件


使用:

10、导入程序集和引用其中的名称空间:

然后选 带 Framework 的



  1. <UserControl x:Class="WpfControlLibrary3.UserControl1"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6. xmlns:local="clr-namespace:WpfControlLibrary3"
  7. mc:Ignorable="d"
  8. d:DesignHeight="160" d:DesignWidth="240">
  9. <Grid>
  10. <Canvas>
  11. <Label Canvas.Left="12" Canvas.Top="12" Content="第一部分" Height="28" Name="label1"/>
  12. <Label Canvas.Left="12" Canvas.Top="46" Content="第二部分" Height="28" Name="label2"/>
  13. <Label Canvas.Left="12" Canvas.Top="80" Content="第三部分" Height="28" Name="label3"/>
  14. <TextBox Canvas.Left="88" Canvas.Top="14" Height="23" Name="textBox1" Width="140"/>
  15. <TextBox Canvas.Left="88" Canvas.Top="48" Height="23" Name="textBox2" Width="140"/>
  16. <TextBox Canvas.Left="88" Canvas.Top="82" Height="23" Name="textBox3" Width="140"/>
  17. <Button Canvas.Left="88" Canvas.Top="125" Content="计算" Height="23" Name="button1" Width="140" Click="button_Click"/>
  18. </Canvas>
  19. </Grid>
  20. </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 控件

  1. using System.Windows.Forms;
  2. using WindowsFormsControlLibrary1;
  3. namespace WpfApp1
  4. {
  5. public partial class UserControl1 : UserControl
  6. {
  7. private Form1 _form1;
  8. public UserControl1()
  9. {
  10. InitializeComponent();
  11. _form1 = new Form1();
  12. _form1.TopLevel = false;
  13. _form1.Dock = DockStyle.Fill;
  14. this.Controls.Add(_form1);
  15. _form1.Show();
  16. }
  17. }
  18. }
复制代码

在 主界面中 WindowsFormsHost 加入标签,在代码中加载 Winform 的控件,借助Winform控件 加载 winform 窗体

  1. <Grid>
  2. <WindowsFormsHost Name="windowsFormsHost" />
  3. </Grid>
复制代码
  1. using System.Windows;
  2. namespace WpfApp1
  3. {
  4. /// <summary>
  5. /// MainWindow.xaml 的交互逻辑
  6. /// </summary>
  7. public partial class MainWindow : Window
  8. {
  9. public MainWindow()
  10. {
  11. InitializeComponent();
  12. UserControl1 userControl1 = new UserControl1();
  13. windowsFormsHost.Child = userControl1;
  14. }
  15. }
  16. }
复制代码

13、动画

动画有三种:
线性动画:DouleAnmim
关键帧动画:DoubleAnimationUsingkeyFrams
路径动画:DoubleAnimationUsingPath

  1. <Grid>
  2. <StackPanel>
  3. <Button x:Name="btn" Width="100" Height="24" Content="带动画的按钮" Click="Button_Click"/>
  4. <Button x:Name="btn2" Width="100" Height="24" Content="带动画的按钮" Click="Button_Click2"/>
  5. <Button x:Name="btn3" Width="100" Height="24" Content="带动画的按钮" Click="Button_Click3"/>
  6. </StackPanel>
  7. </Grid>
复制代码
  1. #define C
  2. using System;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Media.Animation;
  6. namespace WpfApp1
  7. {
  8. /// <summary>
  9. /// MainWindow.xaml 的交互逻辑
  10. /// </summary>
  11. public partial class MainWindow : Window
  12. {
  13. public MainWindow()
  14. {
  15. InitializeComponent();
  16. }
  17. private void Button_Click(object sender, RoutedEventArgs e)
  18. {
  19. //创建一个双精度的动画
  20. DoubleAnimation animation = new DoubleAnimation();
  21. animation.From = btn.Width;//设置动画的初始值
  22. animation.To = btn.Width - 30;//设置动画的结束值
  23. animation.Duration = TimeSpan.FromSeconds(2);//设置动画的持续时间
  24. //在当前按钮上实行该动画
  25. btn.BeginAnimation(Button.WidthProperty,
  26. animation);
  27. }
  28. private void Button_Click2(object sender, RoutedEventArgs e)
  29. {
  30. //创建一个双精度的动画
  31. DoubleAnimation animation = new DoubleAnimation();
  32. animation.From = btn2.Width;//设置动画的初始值
  33. animation.To = btn2.Width - 30;//设置动画的结束值
  34. animation.Duration = TimeSpan.FromSeconds(2);//设置动画的持续时间
  35. animation.AutoReverse = true; //是否往返执行
  36. animation.RepeatBehavior = RepeatBehavior.Forever; //执行周期
  37. //在当前按钮上实行该动画
  38. btn2.BeginAnimation(Button.WidthProperty,
  39. animation);
  40. }
  41. private void Button_Click3(object sender, RoutedEventArgs e)
  42. {
  43. //创建一个双精度的动画
  44. DoubleAnimation animation = new DoubleAnimation();
  45. animation.From = btn3.Width;//设置动画的初始值
  46. animation.To = btn3.Width - 30;//设置动画的结束值
  47. animation.Duration = TimeSpan.FromSeconds(2);//设置动画的持续时间
  48. animation.AutoReverse = true; //是否往返执行
  49. animation.RepeatBehavior = new RepeatBehavior(5);//重复5次
  50. animation.Completed += Animation_Completed;//动画结束的回调
  51. //在当前按钮上实行该动画
  52. btn3.BeginAnimation(Button.WidthProperty,
  53. animation);
  54. }
  55. private void Animation_Completed(object sender,EventArgs e)
  56. {
  57. btn3.Content = "动画已完成";
  58. }
  59. }
  60. }
复制代码

14、WPF 和 Prism

其他

1、获取当前文件目录

  1. string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行