〇、上位機,分層架構
界面層
要實現的功能:
展示數據
獲取數據
發送數據
數據層
要實現的功能:
轉換數據
打包數據
存取數據
通信層
要實現的功能:
打開連接
關閉連接
讀取數據
寫入數據
實體類
作用:
封裝數據、傳遞數據
工具類
一、通信介紹及簡單測試
一、PLC (Programmable Logic Controller | 可編程邏輯控制器)
簡介:
PLC的英文全稱是"Programmable Logic Controller",中文稱為“可編程邏輯控制器”。這是一種數字運算操作電子系統,專為在工業環境下應用而設計。它采用可編程存儲器,用來在其內部存儲執行邏輯運算、順序控制、定時、計數和算術運算等操作的指令,并通過數字式或模擬式的輸入和輸出,控制各種類型的機械或生產過程。
3
1、操作:西門子 smart2000 ,使用工具進行通訊
VD 4byte
VW 2byte
VB 1byte
V102.0 讀一1bit
VB102 讀1byte
VW102 讀2byte
VD102 讀4byte
二、Modbus
Modbus是一種通信協議,主要用于工業電子設備之間進行數據交換。
通訊的模型:
1、模擬測試(TCP)
所需軟件:
mbpoll.exe
mbslave.exe
激活碼:
注冊碼 對 7和 6 都可以使用
poll 注冊碼
5A5742575C5D10
slave 注冊碼
5455415451475662
建立 slave,即服務端 (poll,客戶端也是類似的)
進行連接 :
設置連接信息
收發信息的具體情況:
1-2、模擬測試(串口)
所需軟件:
創建虛擬串口對:
建立 主站 poll
建立從站 slave
2、存儲區、存儲區代碼、范圍
注:在這里布爾和線圈是一個意思:即一位的數據
注:一個區的空間為: 65536 每個為 2byte 大(short)
3、關于讀寫的功能碼
4、協議分類
注:ModbusASCII因為速度慢,很少被使用
ModbusRTU、ModbusASCII 一般用串口
ModbusTCP 一般用以太網
5、ModbusRTU協議:
舉個例子:
6、ModbusTCP
注:Tx的最后4個字節:00 00 00 02,00 00 表示起始 , 而 00 02 表示讀兩個字節
三、串口
簡介:
一位一位的發送數據(以協上好的頻率(波特率)和格式)
格式:
9針 串口:
分類:
RS-232
短距離通信
RS-422
長距離通信
RS-485
折中,
通常在半雙工的模式下工作
RS-485標準理論上支持長達1200米的傳輸距離
單工: 類似,廣播
半雙工: 類似,對講機
全雙工: 類似,電話
測試:虛擬串口
二、C# 通信庫的使用
1、s7通信庫
1、舉例:寫一個C#與s7的通信
(1)、所需軟件:
S7-PLCSIM Advanced V.30
TIA Portal V17
VD 4byte
VW 2byte
VB 1byte
(2)、界面:
(3)、添加所需庫:
S7netplus
thinger.DataConvertLib
(4)、代碼:
<1>.簡單 測試下 連接-讀寫
using S7.Net;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace WindowsFormsApp1
{public partial class Form1 : Form{public Form1(){InitializeComponent();Test();}Plc plc = null;private void Test(){plc = new Plc(CpuType.S7200Smart, "192.168.2.1", 0, 0);plc.Open();//讀取數據object data = plc.Read("M20.0");this.label1.Text = data.ToString();//寫入數據plc.Write("M20.0", false);//不支持V區直接操作,需要映射成DB1plc.Write("DB1.DBX2000.0", true);plc.Close();}}
}
<2>.簡單 的封裝下
using S7.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace WindowsFormsApp1
{public class S7NetLib{private Plc s7netlib = null; //字段//屬性public CpuType CPUType { get;set; }public string IPAddress { get; set; }public short Rack { get; set; }public short Slot { get; set; }//構造函數,初始化連接 所需的變量public S7NetLib(CpuType cpuType,string ip,short rack,short slot){this.CPUType = cpuType;this.IPAddress = ip;this.Rack = rack;this.Slot = slot;}/// <summary>/// 打開PLC連接/// </summary>public void OpenPLC(){if(this.s7netlib == null){s7netlib = new Plc(CPUType,IPAddress,Rack,Slot);}if (!this.s7netlib.IsConnected){s7netlib.ReadTimeout = 1000;//設置超時時間s7netlib.WriteTimeout = 1000;s7netlib.Open();//建立連接}}/// <summary>/// 關閉PLC連接/// </summary>public void ClosePLC(){if(null != this.s7netlib && this.s7netlib.IsConnected){this.s7netlib.Close();}}/// <summary>/// 給plc單個變量寫入數據/// </summary>/// <param name="varAddress">寫到那里去</param>/// <param name="varValue">寫入的值</param>public void WriteDataToPLC(string varAddress, object varValue){OpenPLC();lock (this){this.s7netlib.Write(varAddress, varValue);}}/// <summary>/// 讀取一段數據/// </summary>/// <param name="dataType">存儲區類型</param>/// <param name="db">DB號</param>/// <param name="startByteAdr">開始字節地址</param>/// <param name="count">字節數量</param>/// <returns>字節數組</returns>public byte[] ReadDataFromPLC(DataType dataType,int db,int startByteAdr,int count){lock (this){byte[] bytes = this.s7netlib.ReadBytes(dataType,db,startByteAdr,count);return bytes;}}}
}
using S7.Net;
using System.Windows.Forms;namespace WindowsFormsApp1
{public partial class Form1 : Form{public Form1(){InitializeComponent();Test();}private void Test(){S7NetLib plc = new S7NetLib(CpuType.S7200, "192.168.2.1", 0, 0);plc.WriteDataToPLC("M2.2", true);byte[] dataBytes = null;dataBytes = plc.ReadDataFromPLC(DataType.DataBlock, 1, 0, 10);}}
}
一次讀一個PDU 的長度,不同 CPU的 PDU 的長度不同
2、C# + SQLSERVER
〇、環境
軟件的安裝(服務器端、客戶端)
服務器端:
SQL Sever 下載地址:
https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads
客戶端
服務器端的操作:
客戶端的操作:
兩種連接方式:
SQL Server 的連接配置(增加使用密碼登錄的用戶):
第一步:
第二步:
第三步: 重新啟動,在連接登錄
.
開啟遠程用戶登錄的方式(使用 IP 和 端口號)
第一步:
第二步:
第三步:重啟服務
右鍵我的電腦,點擊屬性
第四步:最后登錄
一、操作軟件:
SQL Server Management Studio
1、兩種連接方式:
2、新建表
然后 ctrl+s 保存
3、添加數據
4、查詢數據
注:注釋是在前面加 –
5、解決不允許保存的彈窗
6、設置主鍵
7、更改數據(增加、刪除、需改)
--查select * from UserT--存--新增insert into UserT(UserName,Password,NickName) values('111','222','333')--刪除delete from UserT where UserName='111'delete from UserT where UserName='111' and Password='888'--修改update UserT set UserName='a' where UserName='111'
到某個指定的數據庫
use QingTongXiaWaterPlant_test
go
修改某一段名的數據類型:
use QingTongXiaWaterPlant_test
go
alter table dbo.WaterFlowData alter column d17 float null;
二、數據庫數據類型
三、數據庫的約束
四、運算符:
五、SQL 語句
(1)、搜索當前存在哪些數據庫:
select * from sysdatabases
(2)、創建數據庫:
1、創建數據庫所在的文件夾
建好的文件
2、執行 sql語句
use master
go
if exists(select * from sysdatabases where name='MISDB') --如果原來存在這個數據庫,則進行刪除
drop database MISDB
go
--創建數據庫
create database MISDB
on primary
(name='MISDB_MData',--必須唯一filename='D:\DB\MISDB_MData.mdf', --物理文件名,主存儲文件size=30MB,filegrowth=10MB
)
,
(name='MISDB_nData',filename='D:\DB\DBMISDB_nData.ndf', --次存儲文件size=20MB,filegrowth=10MB
)
log on
(name='MISDB_log1',filename='D:\DB\MISDB_log1.ldf', --日志文件size=20MB,filegrowth=10MB
)
,
(name='MISDB_log2',filename='D:\DB\MISDB_log2.ldf', --日志文件size=20MB,filegrowth=10MB
)
(3)、創建表:
--創建數據表,是在指定的數據庫里面
use MISDB
go
if exists(select * from sysobjects where name='Department') --如果已經有了 Department 表則對其進行刪除
drop table Department
go
create table Department
(DepartmentId int identity(10,1)primary key,--部門字段值,由系統自動生成,從10開始,每次增加1 primary key 是主鍵的標識DepartmentName varchar(50)not null
)
go
if exists(select * from sysobjects where name='Post') --如果已經有了 Post 表則對其進行刪除
drop table Post
go
create table Post
(PostId int identity(10,1)primary key,PostName varchar(50) not null
)
go
if exists(select * from sysobjects where name='Employee')
drop table Employee
go
create table Employee
(EmplyeeId int identity(100,1) primary key,EmplyeeName varchar(50) not null,Gender char(2) not null check(Gender='男' or Gender='女'),NowAddress nvarchar(100) default('地址不詳'),IdNo char(18) not null check(len(Idno)=18),--檢查約束WeiXinNumber varchar(20)not null,PhoneNumber varchar(50) not null,OtherWork nvarchar(50) not null,EntryDate datetime not null,PostId int references Post(PostId), --外鍵引用DepartmentId int references Department(DepartmentId) --外鍵引用
)
go
(4)、簡單的 增、刪、改、查
--查select * from UserT--存--新增insert into UserT(UserName,Password,NickName) values('111','222','333')--刪除delete from UserT where UserName='111'delete from UserT where UserName='111' and Password='888'--修改update UserT set UserName='a' where UserName='111'
到某個指定的數據庫
use QingTongXiaWaterPlant_test
go
修改某一段名的數據類型:
use QingTongXiaWaterPlant_test
go
alter table dbo.WaterFlowData alter column d17 float null;
(5)、增加
use MISDB
go
select * from Department
select * from Post
select * from Employeeinsert 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 RealDataif @Index='PAC1'begin set @dosage =js_cod/3;endif @Index='PAC2'begin set @dosage =js_cod/2;endEND
修改
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 RealDataif @Index='PAC1'begin set @dosage =js_cod/3;endif @Index='PAC2'begin set @dosage =js_cod/2;endEND
執行的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(){//創建建立連接的對象 -- SqlConnectionSqlConnection 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(){//創建建立連接的對象 -- SqlConnectionSqlConnection 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(){//創建建立連接的對象 -- SqlConnectionSqlConnection conn = new SqlConnection(connString1);//要執行的 sql 語句string sql = "delete from Employee where EmployId=102";//實例化 要執行 sql的對象 -- SqlCommandSqlCommand cmd = new SqlCommand(sql, conn);//建立連接conn.Open();//執行 sql語句int result = cmd.ExecuteNonQuery();//關閉練級conn.Close();Console.WriteLine("受影響的行數:" + result);}//執行查詢結果為1個的 sql 語句public void GetSingleResult(){//創建建立連接的對象 -- SqlConnectionSqlConnection conn = new SqlConnection(connString1);//要執行的 sql 語句string sql = "select EmployeeName from Employee where EmployId=101";//實例化 要執行 sql的對象 -- SqlCommandSqlCommand cmd = new SqlCommand(sql, conn);//建立連接conn.Open();//執行 sql語句 ExecuteScalar 是執行只有一個返回結果的sql 語句object result = cmd.ExecuteScalar();//關閉連接conn.Close();Console.WriteLine(result);}//執行查詢結果為1個的 sql 語句public void GetSingleResult2(){//創建建立連接的對象 -- SqlConnectionSqlConnection conn = new SqlConnection(connString1);//要執行的 sql 語句string sql = "select 員工總數=count(*)from Employee";//實例化 要執行 sql的對象 -- SqlCommandSqlCommand 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(){//創建建立連接的對象 -- SqlConnectionSqlConnection conn = new SqlConnection(connString1);//要執行的 sql 語句string sql = "select EmployeeName,Gender,NowAddress from Employee";//實例化 要執行 sql的對象 -- SqlCommandSqlCommand 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(){//創建建立連接的對象 -- SqlConnectionSqlConnection conn = new SqlConnection(connString1);//要執行的 sql 語句string sql = "select EmployeeName,Gender,NowAddress from Employee";sql += ";select DepartmentId,DepartmentName from Department";//實例化 要執行 sql的對象 -- SqlCommandSqlCommand 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(){//創建建立連接的對象 -- SqlConnectionSqlConnection 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的對象 -- SqlCommandSqlCommand 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
GOCREATE PROCEDURE TestProcedure@Parameter1 Int =0,@Parameter2 Int output
AS
BEGINSET NOCOUNT ONselect * 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
GOALTER PROCEDURE [dbo].[TestProcedure]-- 輸入參數@Parameter1 Int =0,-- 輸出參數@Parameter2 Int output
AS
BEGIN-- 為了不返回 每條sql 影響多少條記錄的信息SET NOCOUNT ONselect * from UserT;Set @Parameter2 = 999;
END
執行
declare @Parameter2 int;exec TestProcedure @Parameter1=20, @Parameter2= @Parameter2 output;select @Parameter2 as Parameter2;
3、NModbus4 通訊庫的使用
1、使用串口,封裝 NModbus4 庫
安裝 NModbus4 庫:
封裝的代碼:
using Modbus.Device;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace WindowsFormsApp1
{/// <summary>/// 基于NModbus4的開源庫的二次封裝/// </summary>internal class ModbusRTU{#region 串口打開//聲明.NET串口對象private SerialPort serialPort;//聲明Modbus協議串口主設備對象private ModbusSerialMaster master;// COM1 9600 N 8 1 public bool Connect(string portName, int baudRate,Parity parity,int dataBits,StopBits stopBits){if(this.serialPort == null && this.serialPort.IsOpen){this.serialPort.Close();}try{//創建.NET串口對象this.serialPort = new SerialPort(portName,baudRate, parity,dataBits,stopBits);//設置串口的讀寫超時時間(防止長時間阻塞)this.serialPort.ReadTimeout = 1000;this.serialPort.WriteTimeout = 1000;//打開 .NET 串口this.serialPort.Open();//使用 Modbus串口工廠方法 創建 Modbus串口主設備 對象master = ModbusSerialMaster.CreateRtu(this.serialPort);return true;}catch(Exception ex){//打印異常信息throw new Exception("[串口]打開失敗,"+ex.Message);}}#endregion#region 關閉串口public void DisConnect(){if(this.serialPort != null && this.serialPort.IsOpen){//this.serialPort?.Close();this.serialPort.Close();}master = null;}#endregion#region 讀取數據/// <summary>/// 【01】功能碼:讀取輸出線圈/// </summary>/// <param name="slaveId">從站地址</param>/// <param name="start">起始線圈地址</param>/// <param name="length">線圈的數量</param>/// <returns>返回bool數組</returns>/// <exception cref="Exception"></exception>public bool[]ReadOutputCoils(byte slaveId,ushort start,ushort length){try{//Coils 線圈的意思return this.master.ReadCoils(slaveId, start, length);}catch(Exception ex){throw new Exception("[讀取輸出線程]失敗" + ex.Message);}}/// <summary>/// [02] 功能碼:讀取輸入線圈/// </summary>/// <param name="slaveId">從站地址</param>/// <param name="start">起始線圈地址</param>/// <param name="length">線圈的數量</param>/// <returns>返回bool數組</returns>/// <exception cref="Exception"></exception>public bool[] ReadInputCoils(byte slaveId, ushort start, ushort length){try{return this.master.ReadInputs(slaveId, start, length);}catch (Exception ex){throw new Exception("[讀取輸入線圈]失敗:" + ex.Message);}}// 一個寄存器是兩個 字節的大小/// <summary>/// 【03】 功能碼:讀取輸出寄存器/// </summary>/// <param name="slaveId">從站地址</param>/// <param name="start">起始寄存器地址</param>/// <param name="length">寄存器的數量</param>/// <returns>返回byte數組</returns>/// <exception cref="Exception"></exception>public byte[] ReadHoldingRegister(byte slaveId,ushort start,ushort length){try{//獲取數據數組ushort[] data = this.master.ReadHoldingRegisters(slaveId, start, length);// 一個寄存器是兩個 字節的大小//把ushort類型數組,轉換成List字節數組List<byte> result = new List<byte>();foreach(var item in data){result.AddRange(BitConverter.GetBytes(item));}return result.ToArray();}catch(Exception ex){throw new Exception("[讀取輸出寄存器]失敗," + ex.Message);}}/// <summary>/// [04] 功能碼:讀取輸入寄存器/// </summary>/// <param name="slaveId">從站地址</param>/// <param name="start">起始寄存器地址</param>/// <param name="length">寄存器的數量</param>/// <returns>返回byte數組</returns>/// <exception cref="Exception"></exception>public byte[] ReadInputRegister(byte slaveId,ushort start,ushort length){try{//獲取數據數組ushort[] data = this.master.ReadInputRegisters(slaveId, start, length);//把ushort類型的數組,轉換成List字節數組List<byte> result = new List<byte>();foreach (var item in data){result.AddRange(BitConverter.GetBytes(item));}return result.ToArray();}catch(Exception ex){throw new Exception("[讀取輸入寄存器]失敗" + ex.Message);}}#endregion#region 寫入數據/// <summary>/// [05] 功能碼:預置單線圈/// </summary>/// <param name="slaveId">從站地址</param>/// <param name="start">當前線圈地址</param>/// <param name="value">線圈的值</param>/// <returns></returns>/// <exception cref="Exception"></exception>public bool PreSetSingleCoil(byte slaveId,ushort start,bool value){try{this.master.WriteSingleCoil(slaveId, start, value);return true;}catch(Exception ex){throw new Exception("[預置單線圈]失敗," + ex.Message);}}/// <summary>/// [06]功能碼:預置單寄存器/// </summary>/// <param name="slaveId">從站地址</param>/// <param name="address">寄存器地址</param>/// <param name="value">字節地址(2個字節)</param>/// <returns></returns>/// <exception cref="Exception"></exception>public bool PreSetSingleRegister(byte slaveId,ushort address,byte[] value){try{this.master.WriteSingleRegister(slaveId, address, BitConverter.ToUInt16(value, 0));return true;}catch (Exception ex){throw new Exception("【預置單寄存器】失敗," + ex.Message);}}public bool PreSetSingleRegister(byte slaveId,ushort address,short value){return PreSetSingleRegister(slaveId, address, BitConverter.GetBytes(value));}public bool PreSetSingleRegister(byte slaveId,ushort address,ushort value){return PreSetSingleRegister(slaveId, address, BitConverter.GetBytes(value));}/// <summary>/// 【0F】 功能碼 預置多個線圈/// </summary>/// <param name="slaveId">從站地址</param>/// <param name="start">線圈開始地址</param>/// <param name="value">布爾數組</param>/// <returns></returns>/// <exception cref="Exception"></exception>public bool PreSetMutiCoils(byte slaveId,ushort start,bool[] value){try{this.master.WriteMultipleCoils(slaveId, start, value);return true;}catch(Exception ex){throw new Exception("[預制多線圈]失敗," + ex.Message);}}/// <summary>/// [10] 功能碼:預制多個寄存器/// </summary>/// <param name="slaveId">從站地址</param>/// <param name="start">寄存器開始地址</param>/// <param name="values">字節數組</param>/// <returns></returns>/// <exception cref="Exception"></exception>public bool PreSetMultiRegister(byte slaveId,ushort start, byte[] values){//必須是偶數字節// 因為兩字節 , 才是也給寄存器的大小if(values == null||values.Length == 0 || values.Length%2 == 1){return false;}//將字節數組轉換成ushort數組ushort[] data = new ushort[values.Length / 2];for (int i = 0; i < values.Length; i += 2){data[i] = BitConverter.ToUInt16(values, i);}try{this.master.WriteMultipleRegisters(slaveId, start, data);return true;}catch(Exception ex){throw new Exception("[預制多寄存器]失敗,"+ex.Message);}}/// <summary>/// [0F] 功能碼:預制多個線圈/// </summary>/// <param name="slaveId">站地址</param>/// <param name="start">線圈開始地址</param>/// <param name="value">布爾數組</param>/// <returns></returns>/// <exception cref="Exception"></exception>public bool PreSetMultiCoils(byte slaveId,ushort start,bool[] value){try{this.master.WriteMultipleCoils(slaveId,start,value);return true;}catch (Exception ex) {throw new Exception("[預制多個線圈]失敗" + ex.Message);}}#endregion}
}
三、手寫通信庫
四、WPF基本使用
0、xaml 的基礎操作
xaml是一種聲明型語言,一般來講,一個標簽就是一個對象;而一個標簽的屬性就是一個對象的屬性。
給標簽屬性賦值有三種方式:
1、 Attribute = Value 形式
畫一個 長方形
<Rectangle Width="100" Height="80" Stroke="Black"/>
畫一個三角形
<Path Data="M 0,0 L 200,100 L 100,200 Z" Stroke="Black" Fill="Red"/>
將一個字符串轉換成標簽(對象)的寫法:
MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp1"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Window.Resources><local:Dog x:Key="dog1" Name="Bob1"/><local:Dog x:Key="dog2" Name="Bob2"/><local:Dog x:Key="dog3" Name="Bob3" Child="123"/></Window.Resources><Grid><Button Content="Hello!" Width="120" Height="30" Click="Button_Click"/></Grid>
</Window>
Dog.cs
using System.ComponentModel;
using System.Globalization;namespace WpfApp1
{//為類添加轉換規則[TypeConverterAttribute(typeof(NameToDogTypeConverter))]public class Dog{public string Name { get; set; }public Dog Child { get; set; }}public class NameToDogTypeConverter : TypeConverter{//將字符串轉成 Dog 的規則public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value){string name = value.ToString();Dog child = new Dog();child.Name = name;return child;}}
}
MainWindow.xaml.cs
using System.Windows;namespace WpfApp1
{/// <summary>/// MainWindow.xaml 的交互邏輯/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void Button_Click(object sender, RoutedEventArgs e){Dog dog =this.FindResource("dog3") as Dog; ;//找到字典資源中 標簽對象的方法if(null != dog){//取出標簽對象中的屬性MessageBox.Show(dog.Name + "/" + dog.Child.Name);}}}
}
另一種等價的添加屬性 的方式:
<Button Content="登錄" FontSize="20" Height="50" Width="300"/>
<Button Content="登錄"><Setter Property="Background" Value="Red"/><Setter Property="FontSize" Value="20"/><Setter Property="Height" Value="50"/><Setter Property="Width" Value="300"/></Button>
2、屬性標簽
形如:
<LinearGradientBrush.StartPoint>
就是屬性標簽,它不是一個對象,而是對象的屬性,用標簽的形式來寫
例子 1:
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Grid><Rectangle Width="200" Height="160" Stroke="Blue"><Rectangle.Fill><LinearGradientBrush><LinearGradientBrush.StartPoint><Point X="0" Y="0"/></LinearGradientBrush.StartPoint><LinearGradientBrush.EndPoint><Point X="1" Y="1"/></LinearGradientBrush.EndPoint><LinearGradientBrush.GradientStops><GradientStopCollection><GradientStop Offset="0.2" Color="LightBlue"/><GradientStop Offset="0.7" Color="DarkBlue"/><GradientStop Offset="1.0" Color="Blue"/></GradientStopCollection></LinearGradientBrush.GradientStops></LinearGradientBrush></Rectangle.Fill></Rectangle></Grid>
</Window>
例子 2:
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Grid><Button Width="120" Height="30"><Button.Content><Rectangle Width="20" Height="20" Stroke="DarkGreen" Fill="LawnGreen"/></Button.Content></Button></Grid>
</Window>
3、標簽擴展
1、創建一個項目
程序入口:
默認入口點:WPF 應用程序的默認入口點是 App.xaml 和 App.xaml.cs 文件。在這些文件中定義了應用程序的啟動邏輯和主窗口。
自定義入口點:如果需要,可以在代碼中定義一個 Main 方法并在其中創建和運行 Application 對象,但這不是必需的,除非你有特定的初始化需求。
手寫函數函數入口(一般不需要):
// Entry point defined in a custom Main method (if needed)
public static class Program
{[STAThread]public static void Main(){var app = new App();app.InitializeComponent();app.Run();}
}
// App.xaml.cs
using System.Windows;namespace MyWpfApp
{public partial class App : Application{// Application startup logic can be placed hereprotected override void OnStartup(StartupEventArgs e){base.OnStartup(e);// Custom startup logic (if needed)}protected override void OnExit(ExitEventArgs e){base.OnExit(e);// Custom exit logic (if needed)}}
}
窗體 xaml 文件的解讀:
2、模擬一個文本編輯的界面(使用控件:Grid | StackPanel | Button | TextBox)
準備
button的屬性: Width HorizontalAlignment VerticalAlignment Height
<Grid><Button Width="200" HorizontalAlignment="Left" VerticalAlignment="Top" Height="40"/><Button Width="200" HorizontalAlignment="Center" VerticalAlignment="Top" Height="40"/><Button Width="200" HorizontalAlignment="Right" VerticalAlignment="Top" Height="40"/><Button Width="200" HorizontalAlignment="Left" VerticalAlignment="Center" Height="40"/><Button Width="200" HorizontalAlignment="Center" VerticalAlignment="Center" Height="40"/><Button Width="200" HorizontalAlignment="Right" VerticalAlignment="Center" Height="40"/><Button Width="200" HorizontalAlignment="Left" VerticalAlignment="Bottom" Height="40"/><Button Width="200" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="40"/><Button Width="200" HorizontalAlignment="Right" VerticalAlignment="Bottom" Height="40"/></Grid>
Stackanel控件:
.
占用多列的寫法:
Grid.ColumnSpan=“2”
<StackPanel Orientation="Vertical" HorizontalAlignment="Center"><Button Height="20" Width="70"/><Button Height="20" Width="70"/><Button Height="20" Width="70"/></StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"><Button Height="20" Width="70"/><Button Height="20" Width="70"/><Button Height="20" Width="70"/></StackPanel>
Grid控件:
<Grid ShowGridLines="True"><Grid.RowDefinitions><RowDefinition Height="1*"/><RowDefinition Height="1*"/><RowDefinition Height="1*"/><RowDefinition Height="1*"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/></Grid.ColumnDefinitions><Button Grid.Row="1" Grid.Column="1">1,1</Button><Button Grid.Row="1" Grid.Column="2">1,2</Button><Button Grid.Row="1" Grid.Column="3">1,3</Button><Button Grid.Row="2" Grid.Column="1">2,1</Button><Button Grid.Row="2" Grid.Column="2">2,2</Button><Button Grid.Row="2" Grid.Column="3">2,3</Button></Grid>
Grid 的三種長度設置:
AUTO 安內容來
絕對寬高 每個單位是 1/96英寸
“1*” 按比例來
TextBox 文本編輯的控件
<TextBox TextWrapping="Wrap"/>
應用
<Window x:Class="WpfApp1.EditWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp1"mc:Ignorable="d"Title="EditWindow" Height="450" Width="800"><Grid><Grid.RowDefinitions><RowDefinition Height="20"/><RowDefinition Height="20"/><RowDefinition Height="1*"/><RowDefinition Height="20"/></Grid.RowDefinitions><StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal"><Button Height="20" Width="70" Content="文件"/><Button Height="20" Width="70" Content="編輯"/><Button Height="20" Width="70" Content="查看"/><Button Height="20" Width="70" Content="外觀"/><Button Height="20" Width="70" Content="設置"/></StackPanel><StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal"><Button Height="20" Width="20" Content="1"/><Button Height="20" Width="20" Content="2"/><Button Height="20" Width="20" Content="3"/><Button Height="20" Width="20" Content="4"/><Button Height="20" Width="20" Content="5"/></StackPanel><Grid Grid.Row="2" Grid.Column="0"><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="40"/><ColumnDefinition/></Grid.ColumnDefinitions><StackPanel Grid.Column="0" Grid.Row="0"><Button Height="20" Content="1"/><Button Height="20" Content="2"/><Button Height="20" Content="3"/><Button Height="20" Content="4"/><Button Height="20" Content="5"/><Button Height="20" Content="6"/><Button Height="20" Content="7"/><Button Height="20" Content="8"/><Button Height="20" Content="9"/><Button Height="20" Content="10"/><Button Height="20" Content="11"/><Button Height="20" Content="12"/><Button Height="20" Content="13"/><Button Height="20" Content="14"/><Button Height="20" Content="15"/><Button Height="20" Content="16"/><Button Height="20" Content="17"/></StackPanel><TextBox Grid.Column="1" TextWrapping="Wrap"/></Grid></Grid><Grid Grid.Row="3" Grid.Column="0"><Grid.ColumnDefinitions><ColumnDefinition Width="auto"/><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/><ColumnDefinition Width="1*"/></Grid.ColumnDefinitions><Button Grid.Column="0">Normal text file</Button><Button Grid.Column="1">Length:1,125</Button><Button Grid.Column="2">lines:26</Button><Button Grid.Column="3">Ln:6 Col:57 Sel:3</Button><Button Grid.Column="4">1</Button><Button Grid.Column="5">Windows(CR LF)</Button><Button Grid.Column="6">UTF-8-BOM</Button><Button Grid.Column="7">INS</Button></Grid></Grid>
</Window>
2-2 布局器的使用:
1、StackPanel 水平或垂直排列元素、Orientation 屬性分別為:Horizontal / Verical
2、WrapPanel 水平或垂直排列元素、剩余控件不足會進行換行、換列的排布
3、DockPanel 根據容器的邊界、元素進行 Dock.Top 、Left 、Right 、Bottom
4、Grid 類似 table表格
5、UniformGrid 指定行和列的數量,均勻有限的容器空間
6、Canvas 使用固定的坐標設置元素的位置
3、樣式
樣式寫在:
< Window.Resources > 里的 < Style > 里 //定義
在標簽里加屬性Style: Style=“{StaticResource LoginStyle}” //使用
StaticResource 靜態加載
DynamicResource 動態加載,在運行的時候,改變 xaml 文件內容,樣式是會發生改變的
<Window x:Class="WpfApp1.EditWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp1"mc:Ignorable="d"Title="EditWindow" Height="450" Width="800"><Window.Resources><Style TargetType="Button"><Setter Property="Background" Value="WhiteSmoke"/><Setter Property="FontSize" Value="20"/><Setter Property="Height" Value="50"/><Setter Property="Width" Value="300"/><Setter Property="Margin" Value="20,10"/></Style><Style x:Key="LoginStyle" TargetType="Button"><Setter Property="Background" Value="Green"/><Setter Property="FontSize" Value="20"/><Setter Property="Height" Value="50"/><Setter Property="Width" Value="300"/></Style><Style x:Key="QuitStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button} }"><Setter Property="Background" Value="Red"/></Style></Window.Resources><StackPanel><Button Style="{StaticResource LoginStyle}" Content="登錄"/><Button Style="{DynamicResource QuitStyle}" Content="退出"/><Button Content="忘記密碼"/></StackPanel></Window>
繼承:
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="登錄界面" Height="270" Width="500" ResizeMode="NoResize"><Window.Resources><Style x:Key="baseButtonStyle" TargetType="Button"><Setter Property="FontSize" Value="30"/><Setter Property="Foreground" Value="Blue"/></Style><Style x:Key="defaultButtonStyle" TargetType="Button" BasedOn="{StaticResource baseButtonStyle}"><Setter Property="Width" Value="100"/><Setter Property="Height" Value="50"/></Style></Window.Resources><Grid><Button Style="{StaticResource defaultButtonStyle}" Content="ghyu"/></Grid>
</Window>
4、添加資源字典
第一步:添加資源字典 xaml 文件
資源字典文件:Dictionary1.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Style TargetType="Button"><Setter Property="Background" Value="WhiteSmoke"/><Setter Property="FontSize" Value="20"/><Setter Property="Height" Value="50"/><Setter Property="Width" Value="300"/><Setter Property="Margin" Value="20,10"/></Style><Style x:Key="LoginStyle" TargetType="Button"><Setter Property="Background" Value="Green"/><Setter Property="FontSize" Value="20"/><Setter Property="Height" Value="50"/><Setter Property="Width" Value="300"/></Style><Style x:Key="QuitStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button} }"><Setter Property="Background" Value="Red"/></Style>
</ResourceDictionary>
第二步:在 app.xml 文件中引入 資源字典文件
<ResourceDictionary Source="/WpfApp1;component/Dictionary1.xaml"/>這里的 WpfApp1 是 命名空間Dictionary1.xaml 是 要加載的文件名
<Application x:Class="WpfApp1.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:WpfApp1"StartupUri="EditWindow.xaml"><Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="/WpfApp1;component/Dictionary1.xaml"/></ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources>
</Application>
第三步:在標簽中,可以直接調用
<Window x:Class="WpfApp1.EditWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp1"mc:Ignorable="d"Title="EditWindow" Height="450" Width="800"><StackPanel><Button Style="{StaticResource LoginStyle}" Content="登錄"/><Button Style="{DynamicResource QuitStyle}" Content="退出"/><Button Content="忘記密碼"/></StackPanel>
</Window>
5、用模板自定義一個帶圓角的 Button 控件 及 觸發器 的寫法
<ControlTemplate TargetType="Button">
里 TargetType=“Button” 和 TargetTye=“{x:Type Button}” 是一樣的
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="6">
在這一行中,{TemplateBinding Background}" 表示從原 button 標簽中去取 叫 Background 的屬性
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp1"mc:Ignorable="d"Title="123" Height="450" Width="800"><Grid><Button Content="btn" Background="Red" BorderBrush="Black" FontSize="20" Width="200" Height="30" BorderThickness="3"><Button.Template><ControlTemplate TargetType="Button"><Border x:Name="boder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="6"><TextBlock Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/></Border><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter TargetName="boder" Property="Background" Value="Black"/></Trigger><Trigger Property="IsPressed" Value="True"><Setter TargetName="boder" Property="Background" Value="WhiteSmoke"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Button.Template></Button></Grid>
</Window>
解讀:
Grid: 一個布局容器,用于布局子元素。在這個例子中,它包含了一個 Button 控件。
Button: 一個按鈕控件,具有以下屬性:
Content=“btn”: 按鈕的顯示文本為 “btn”。
Background=“Red”: 按鈕的背景顏色為紅色。
BorderBrush=“Black”: 按鈕的邊框顏色為黑色。
FontSize=“20”: 按鈕文本的字體大小為 20。
Width=“200”: 按鈕的寬度為 200 像素。
Height=“30”: 按鈕的高度為 30 像素。
BorderThickness=“3”: 按鈕的邊框厚度為 3 像素。
ControlTemplate: 定義了 Button 控件的外觀模板。TargetType=“Button” 指定這個模板用于 Button 控件。
Border: 包含了按鈕的主要視覺部分。
x:Name=“boder”: 給 Border 起了一個名字 boder,以便在觸發器中引用。
Background=“{TemplateBinding Background}”: Border 的背景顏色綁定到按鈕的 Background 屬性。
BorderBrush=“{TemplateBinding BorderBrush}”: Border 的邊框顏色綁定到按鈕的 BorderBrush 屬性。
BorderThickness=“{TemplateBinding BorderThickness}”: Border 的邊框厚度綁定到按鈕的 BorderThickness 屬性。
CornerRadius=“6”: Border 的圓角半徑設置為 6 像素,使邊角有一定的圓潤效果。
TextBlock: 顯示按鈕的文本內容。
Text=“{TemplateBinding Content}”: TextBlock 的文本綁定到按鈕的 Content 屬性。
HorizontalAlignment=“Center”: 文本在水平方向居中對齊。
VerticalAlignment=“Center”: 文本在垂直方向居中對齊.
5-2、觸發器 的另一些實踐
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="登錄界面" Height="270" Width="500"><Window.Resources><Style x:Key="defaultButtonStyle" TargetType="Button"><Setter Property="Width" Value="100"/><Setter Property="Height" Value="30"/><Style.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="Foreground" Value="Red"/><Setter Property="FontSize" Value="30"/></Trigger><Trigger Property="IsMouseOver" Value="False"><Setter Property="Foreground" Value="Blue"/><Setter Property="FontSize" Value="20"/></Trigger></Style.Triggers></Style><Style x:Key="defaultButtonStyle2" TargetType="Button"><Setter Property="Width" Value="100"/><Setter Property="Height" Value="30"/><Style.Triggers><MultiTrigger><MultiTrigger.Conditions><Condition Property="IsMouseOver" Value="true"/><Condition Property="IsFocused" Value="True"/></MultiTrigger.Conditions><MultiTrigger.Setters><Setter Property="Foreground" Value="Red"/></MultiTrigger.Setters></MultiTrigger></Style.Triggers></Style><Style x:Key="defaultButtonStyle3" TargetType="Button"><Setter Property="Width" Value="100"/><Setter Property="Height" Value="30"/><Style.Triggers><EventTrigger RoutedEvent="Mouse.MouseEnter"><EventTrigger.Actions><BeginStoryboard><Storyboard><DoubleAnimation Duration="0:0:0.2"Storyboard.TargetProperty="FontSize"To="30"></DoubleAnimation></Storyboard></BeginStoryboard></EventTrigger.Actions></EventTrigger></Style.Triggers></Style></Window.Resources><StackPanel><Button Style="{StaticResource defaultButtonStyle}" Content="Hello"/><Button Style="{StaticResource defaultButtonStyle2}" Content="Hello"/><Button Style="{StaticResource defaultButtonStyle3}" Content="Hello"/></StackPanel>
</Window>
5-3、生成模板副本:
將 模板放在 資源字典中:
5-4、控件模板
5-5、數據模板
第一個例子:
第二個例子:
6、 button 的 和 點擊事件 的寫法:
6-2、添加點擊事件的兩種方式:
1 直接在 xaml 代碼中進行添加
2 根據名字找到控件的 點擊事件,在 cs 代碼中添加
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:sys="clr-namespace:System;assembly=mscorlib"Title="MainWindow" Height="450" Width="800"><Window.Resources><sys:String x:Key="stringHello">Hello WPF!</sys:String></Window.Resources><Grid><TextBlock Height="24" Width="120" Background="LightBlue"Text="{StaticResource ResourceKey=stringHello}"/></Grid>
</Window>
7-1、控件間的屬性綁定
<Grid><StackPanel><Slider x:Name="slider" Margin="5"/><TextBoxHeight="30"Margin="5"Text="{Binding ElementName=slider, Path=Value, Mode=OneTime}"/><!--只進行一次綁定--><TextBoxHeight="30"Margin="5"Text="{Binding ElementName=slider, Path=Value, Mode=OneWay}"/><!--單向綁定--><TextBoxHeight="30"Margin="5"Text="{Binding ElementName=slider, Path=Value}"/><!--默認是雙向綁定--></StackPanel></Grid>
7-2、一個簡單的數據綁定的寫法(屬性的變更通知)
完成前 3 步,可以實現 數據從界面 向 代碼的傳遞
完成后 2 步,可以實現 界面 向 代碼層的數據傳遞
代碼:
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp1"mc:Ignorable="d"Title="登錄界面" Height="270" Width="500" ResizeMode="NoResize"><Grid><Grid.RowDefinitions><RowDefinition Height="15"/><RowDefinition Height="30"/><RowDefinition Height="auto"/><RowDefinition Height="5*"/></Grid.RowDefinitions><TextBox Grid.Row="1" Text="X6337TEB6----登錄系統" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/><Grid Grid.Row="2"><Grid.RowDefinitions><RowDefinition Height="20"/><RowDefinition Height="20"/><RowDefinition Height="20"/><RowDefinition Height="27"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="1*"/><ColumnDefinition Width="auto"/><ColumnDefinition Width="150"/><ColumnDefinition Width="1*"/></Grid.ColumnDefinitions><TextBlock Grid.Row="0" Grid.Column="1" Text="用戶名"/><TextBox Text ="{Binding UserName}" Grid.Row="0" Grid.Column="2" Margin="3,2"/><TextBlock Grid.Row="1" Grid.Column="1" Text="密碼"/><TextBox Text="{Binding PassWord}" Grid.Row="1" Grid.Column="2" Margin="3,2"/><CheckBox Grid.ColumnSpan="2" Grid.Row="2" Grid.Column="1" Content="記住密碼"/><Button Grid.ColumnSpan="2" Grid.Row="3" Grid.Column="1" Content="登錄" Margin="3,1" Click="Button_Click"/></Grid></Grid>
</Window>
using System;
using System.ComponentModel;
using System.Windows;namespace WpfApp1
{/// <summary>/// MainWindow.xaml 的交互邏輯/// </summary>public partial class MainWindow : Window,INotifyPropertyChanged{#region 數據綁定的固定寫法private string _userName;private string _passWord;public string UserName {get { return _userName; }set { _userName = value;RaisePropertyChanged("UserName");} }public string PassWord {get { return _passWord; } set {_passWord = value;RaisePropertyChanged("PassWord");} }public event PropertyChangedEventHandler PropertyChanged;private void RaisePropertyChanged(string propertyName){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}#endregionpublic MainWindow(){InitializeComponent();this.DataContext = this;}/// <summary>/// 登錄按鈕/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Button_Click(object sender, RoutedEventArgs e){Console.WriteLine($"{UserName}-{PassWord}");UserName = "Admin";PassWord = "123";}}
}
8、MVVM(與 7 是同一個界面)
MVVM是為里前后端的分離
MVVM與MVC,VM 是對 C 的升級(依靠的是 雙向的數據屬性 和 單向的命令屬性)
V 的修改 不會影響到 其他部分代碼的編譯
MVVM 和 MVC 的區別
MVVM
M Model
V View
VM ViewModel
MVC
M Model
V View
C Control
8-1.1 帶參的方法的寫法:
傳入 Tag
<Button Grid.Row="0" Command="{Binding ClickBtn}" Tag="a" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Tag}">a</Button>
public ICommand ClickBtn
{get{return new ExecuteCommond((param) =>{// param 是 CommandParameter 傳遞的值string tag = param as string;Console.WriteLine($"Tag: {tag}");});}
}
傳入控件自身
<Button Grid.Row="0" Command="{Binding ClickBtn}" Tag="a" CommandParameter="{Binding RelativeSource={RelativeSource Self}}">a</Button>
public ICommand ClickBtn
{get{return new ExecuteCommond((param) =>{if (param is Button button){var tag = button.Tag; // 獲取按鈕的Tag屬性Console.WriteLine($"Tag: {tag}");}});}
}
多種入參的 ICommand 的實現
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;namespace QIPWaterDeal.ViewModel
{public class ExecuteCommond : ICommand{/// <summary>/// 判斷命令是否可以執行/// </summary>private readonly Func<bool> _canExecute;/// <summary>/// 執行無參數的操作/// </summary>private readonly Action _execute;/// <summary>/// 執行帶參數的操作/// </summary>private readonly Action<object> _executeWithParameter;/// <summary>/// 構造方法(無參數版本)/// </summary>public ExecuteCommond(Action execute, Func<bool> canExecute = null){_execute = execute;_canExecute = canExecute;}/// <summary>/// 構造方法(帶參數版本)/// </summary>public ExecuteCommond(Action<object> executeWithParameter, Func<bool> canExecute = null){_executeWithParameter = executeWithParameter;_canExecute = canExecute;}public event EventHandler CanExecuteChanged;/// <summary>/// 是否可以執行命令/// </summary>public bool CanExecute(object parameter){return _canExecute == null || _canExecute();}/// <summary>/// 執行命令/// </summary>public void Execute(object parameter){if (_execute != null){_execute.Invoke();}else if (_executeWithParameter != null){_executeWithParameter.Invoke(parameter);}}/// <summary>/// 通知CanExecute狀態發生變化/// </summary>public void RaiseCanExecuteChanged(){CanExecuteChanged?.Invoke(this, EventArgs.Empty);}}
}
8-2 MVVM的另一種實踐(對 進行包裝)
一個實際的例子
MainWindow.xml
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="登錄界面" Height="270" Width="500" ResizeMode="NoResize"><Grid><StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"><TextBox x:Name="input1" Width="100" Height="24" Margin="3" Text="{Binding Input1}"></TextBox><TextBox x:Name="input2" Width="100" Height="24" Margin="3" Text="{Binding Input2}"></TextBox><TextBox x:Name="input3" Width="100" Height="24" Margin="3" Text="{Binding Input3}"></TextBox><Button x:Name="btn1" Width="100" Height="24" Margin="3" Content="Add" Command="{Binding AddCommand}"></Button></StackPanel></Grid>
</Window>
NotificationObject
using System.ComponentModel;namespace WpfApp1
{/// <summary>/// VM 的基類/// </summary>public class NotificationObject:INotifyPropertyChanged{public event PropertyChangedEventHandler PropertyChanged;public void RaisePropertyChange(string propertyName){if(this.PropertyChanged != null){this.PropertyChanged.Invoke(this,new PropertyChangedEventArgs(propertyName));}}}
}
DelegateCommand
using System;
using System.Windows.Input;namespace WpfApp1
{public class DelegateCommand:ICommand{public bool CanExecute(object parameter){if(this.CanExecuteFunc == null){return true;}return this.CanExecuteFunc(parameter);}public event EventHandler CanExecuteChanged;public void Execute(object parameter){if(this.ExecuteAction == null){return;}this.ExecuteAction(parameter);}public Action<object> ExecuteAction { get; set; }public Func<object,bool> CanExecuteFunc { get; set; }}
}
MainWindowViewModel
using System;namespace WpfApp1
{internal class MainWindowViewModel : NotificationObject{#region 數據屬性private double input1;public double Input1 {get{ return input1;}set { input1 = value;this.RaisePropertyChange(nameof(Input1));}}private double input2;public double Input2 {get{return input2;}set{input2 = value;this.RaisePropertyChange(nameof(Input2));}}private double input3;public double Input3 {get {return input3;}set {input3 = value;this.RaisePropertyChange(nameof(Input3));}}#endregion#region 命令屬性public DelegateCommand AddCommand { get; set; }private void Add(object parameter){this.Input3 = this.Input1 + this.Input2;}public MainWindowViewModel(){this.AddCommand = new DelegateCommand();this.AddCommand.ExecuteAction = new Action<object>(this.Add);}#endregion}
}
8-3、利用 特性(反射),優化數據變更通知(接口)的寫法
9、寫一個自定義控件(添加 自定義 依賴屬性)
字典資源
加入字典資源
繼承 Button 的自定義控件
使用:
10、導入程序集和引用其中的名稱空間:
然后選 帶 Framework 的
<UserControl x:Class="WpfControlLibrary3.UserControl1"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfControlLibrary3"mc:Ignorable="d" d:DesignHeight="160" d:DesignWidth="240"><Grid><Canvas><Label Canvas.Left="12" Canvas.Top="12" Content="第一部分" Height="28" Name="label1"/><Label Canvas.Left="12" Canvas.Top="46" Content="第二部分" Height="28" Name="label2"/><Label Canvas.Left="12" Canvas.Top="80" Content="第三部分" Height="28" Name="label3"/><TextBox Canvas.Left="88" Canvas.Top="14" Height="23" Name="textBox1" Width="140"/><TextBox Canvas.Left="88" Canvas.Top="48" Height="23" Name="textBox2" Width="140"/><TextBox Canvas.Left="88" Canvas.Top="82" Height="23" Name="textBox3" Width="140"/><Button Canvas.Left="88" Canvas.Top="125" Content="計算" Height="23" Name="button1" Width="140" Click="button_Click"/></Canvas></Grid>
</UserControl>
添加引用:
11、一些 x 命名空間的使用
x:Class
x:ClassModifier
x:Name
x:FieldModifier
12、在WPF中加載 Winform 的 Form
1、在wpf 中添加引用
System.Windows.Forms.Integration
和
System.Windows.Forms.Integration
注:System.Windows.Forms.Integration 在 Net Formwork 4.7.2 中叫 WindowsFormsIntegration
2、創建用戶控件
在wpf 項目中創建 winform 控件
using System.Windows.Forms;
using WindowsFormsControlLibrary1;namespace WpfApp1
{public partial class UserControl1 : UserControl{private Form1 _form1;public UserControl1(){InitializeComponent();_form1 = new Form1();_form1.TopLevel = false;_form1.Dock = DockStyle.Fill;this.Controls.Add(_form1);_form1.Show();}}
}
在 主界面中 WindowsFormsHost 加入標簽,在代碼中加載 Winform 的控件,借助Winform控件 加載 winform 窗體
<Grid><WindowsFormsHost Name="windowsFormsHost" /></Grid>
using System.Windows;
namespace WpfApp1
{/// <summary>/// MainWindow.xaml 的交互邏輯/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();UserControl1 userControl1 = new UserControl1();windowsFormsHost.Child = userControl1;}}
}
13、動畫
動畫有三種:
線性動畫:DouleAnmim
關鍵幀動畫:DoubleAnimationUsingkeyFrams
路徑動畫:DoubleAnimationUsingPath
<Grid><StackPanel><Button x:Name="btn" Width="100" Height="24" Content="帶動畫的按鈕" Click="Button_Click"/><Button x:Name="btn2" Width="100" Height="24" Content="帶動畫的按鈕" Click="Button_Click2"/><Button x:Name="btn3" Width="100" Height="24" Content="帶動畫的按鈕" Click="Button_Click3"/></StackPanel></Grid>
#define C
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
namespace WpfApp1
{/// <summary>/// MainWindow.xaml 的交互邏輯/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void Button_Click(object sender, RoutedEventArgs e){//創建一個雙精度的動畫DoubleAnimation animation = new DoubleAnimation();animation.From = btn.Width;//設置動畫的初始值animation.To = btn.Width - 30;//設置動畫的結束值animation.Duration = TimeSpan.FromSeconds(2);//設置動畫的持續時間//在當前按鈕上實行該動畫btn.BeginAnimation(Button.WidthProperty,animation);}private void Button_Click2(object sender, RoutedEventArgs e){//創建一個雙精度的動畫DoubleAnimation animation = new DoubleAnimation();animation.From = btn2.Width;//設置動畫的初始值animation.To = btn2.Width - 30;//設置動畫的結束值animation.Duration = TimeSpan.FromSeconds(2);//設置動畫的持續時間animation.AutoReverse = true; //是否往返執行animation.RepeatBehavior = RepeatBehavior.Forever; //執行周期//在當前按鈕上實行該動畫btn2.BeginAnimation(Button.WidthProperty,animation);}private void Button_Click3(object sender, RoutedEventArgs e){//創建一個雙精度的動畫DoubleAnimation animation = new DoubleAnimation();animation.From = btn3.Width;//設置動畫的初始值animation.To = btn3.Width - 30;//設置動畫的結束值animation.Duration = TimeSpan.FromSeconds(2);//設置動畫的持續時間animation.AutoReverse = true; //是否往返執行animation.RepeatBehavior = new RepeatBehavior(5);//重復5次animation.Completed += Animation_Completed;//動畫結束的回調//在當前按鈕上實行該動畫btn3.BeginAnimation(Button.WidthProperty,animation);}private void Animation_Completed(object sender,EventArgs e){btn3.Content = "動畫已完成";}}}
14、WPF 和 Prism
其他
1、獲取當前文件目錄
string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;