C#之上位机开发---------C#通信库及WPF的简单实践
- 手机
- 2025-09-04 04:27:01

〇、上位机,分层架构 界面层
要实现的功能: 展示数据 获取数据 发送数据
数据层要实现的功能: 转换数据 打包数据 存取数据
通信层要实现的功能: 打开连接 关闭连接 读取数据 写入数据
实体类作用: 封装数据、传递数据
工具类 一、通信介绍及简单测试 一、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
二、ModbusModbus是一种通信协议,主要用于工业电子设备之间进行数据交换。
通讯的模型:
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 下载地址: .microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:d="http://schemas.microsoft /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、属性标签形如: <LinearGradientBrush.StartPoint> 就是属性标签,它不是一个对象,而是对象的属性,用标签的形式来写 例子 1:
<Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:d="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:d="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:d="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:d="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:d="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:d="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:d="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:d="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /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 /winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft /winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft /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;C#之上位机开发---------C#通信库及WPF的简单实践由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C#之上位机开发---------C#通信库及WPF的简单实践”