C# WPF燃气报警器记录读取串口工具

2024-09-06 23:20

本文主要是介绍C# WPF燃气报警器记录读取串口工具,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C# WPF燃气报警器记录读取串口工具

  • 概要
  • 串口帧数据
  • 布局文件
  • 代码文件
  • 运行效果
  • 源码下载

概要

  • 符合国标文件《GB+15322.2-2019.pdf》串口通信协议定义;
  • 可读取燃气报警器家用版设备历史记录信息等信息;
    在这里插入图片描述
    在这里插入图片描述

串口帧数据

串口通信如何确定一帧数据接收完成是个麻烦事,本文采用最后一次数据接收完成后再过多少毫秒认为一帧数据接收完成,开始解析出来。每次接收到数据更新一次recvTimems 。定时器mTimer定时周期10毫秒,定时器回调函数里判断接收时间超过20ms(这个时间的长短和串口波特率有关)认为一帧数据接收完成。接收数据时间差未超过20ms则将接收数据追加到rxBuf数据缓冲,

long recvTimems = 0;    // 用于计算串口接收完一帧数据
int rxLen = 0;  // 串口接收到的数据长度
byte[] rxBuff = new byte[128];  // 串口数据接收缓存
private static Timer mTimer;    // 定时器,10ms执行一次mTimer = new Timer(recvTimerCalback, null, 0, 10);  // 创建并启动定时器private void recvTimerCalback(object obj)
{//Console.WriteLine("timer callback!" + recvTimems);this.Dispatcher.Invoke(new Action(()=> {// UI线程分离,更新UI数据显示if (((Environment.TickCount - recvTimems) >= 20) && (rxLen > 0)){// 串口接收时间超过X ms认为一帧数据接收完成这里解析处理接收数据.....// 一帧数据处理结束清空数据缓冲Array.Clear(rxBuff, 0, rxBuff.Length);rxLen = 0;}}));  
}private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{SerialPort comPort = (SerialPort)sender;try{recvTimems = Environment.TickCount; // 更新串口数据接收时间//rxBuff[rxLen] = mSerialPort.ReadByte();int readCnt = mSerialPort.BytesToRead;Console.WriteLine("in readCnt:" + readCnt);mSerialPort.Read(rxBuff, rxLen, readCnt);rxLen += readCnt;Console.WriteLine("out rxLen:" + rxLen);}catch (Exception ce){MessageBox.Show(ce.Message);}            }

布局文件

XAML

<Window x:Class="GasAlarmTestTool.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:GasAlarmTestTool"mc:Ignorable="d"Title="燃气报警器接口工具" Height="600" Width="800"><Grid><TabControl><TabItem><TabItem.Header><StackPanel><Label>串口设置</Label></StackPanel></TabItem.Header><StackPanel Orientation="Horizontal"><GroupBox Header="串口" Width="200"><StackPanel><StackPanel Orientation="Horizontal"><Label Margin="3" Height="25" Width="50">端口号</Label><ComboBox x:Name="comboBoxCOM" Margin="3" Height="20" Width="130" DragDrop.Drop="comboBoxCOM_Drop"/></StackPanel><StackPanel Orientation="Horizontal"><Label Margin="3" Height="25" Width="50">波特率</Label><ComboBox x:Name="comboBoxBaudRate" Margin="3" Height="20" Width="130" SelectedIndex="0" IsEditable="True" ></ComboBox></StackPanel><StackPanel Orientation="Horizontal"><Label Margin="3" Height="25" Width="50">数据位</Label><ComboBox x:Name="comboBoxDataBit" Margin="3" Height="20" Width="130" SelectedIndex="3"><ComboBoxItem>5</ComboBoxItem><ComboBoxItem>6</ComboBoxItem><ComboBoxItem>7</ComboBoxItem><ComboBoxItem>8</ComboBoxItem></ComboBox></StackPanel><StackPanel Orientation="Horizontal"><Label Margin="3" Height="25" Width="50">停止位</Label><ComboBox x:Name="comboBoxStopBit" Margin="3" Height="20" Width="130" SelectedIndex="0"><ComboBoxItem>1位</ComboBoxItem><ComboBoxItem>1.5位</ComboBoxItem><ComboBoxItem>2位</ComboBoxItem></ComboBox></StackPanel><StackPanel Orientation="Horizontal"><Label Margin="3" Height="25" Width="50">校验位</Label><ComboBox x:Name="comboBoxSdd" Margin="3" Height="20" Width="130" SelectedIndex="0"><ComboBoxItem>无校验</ComboBoxItem><ComboBoxItem>奇校验</ComboBoxItem><ComboBoxItem>偶校验</ComboBoxItem><ComboBoxItem>1 校验</ComboBoxItem><ComboBoxItem>0 校验</ComboBoxItem></ComboBox></StackPanel><StackPanel Orientation="Horizontal"><Label Margin="3" Height="25" Width="50">流控位</Label><ComboBox x:Name="comboBoxlik" Margin="3" Height="20" Width="130" SelectedIndex="0" ><ComboBoxItem>无流控</ComboBoxItem><ComboBoxItem>RTS/CTS</ComboBoxItem><ComboBoxItem>XON/XOFF</ComboBoxItem></ComboBox></StackPanel><StackPanel Orientation="Horizontal" HorizontalAlignment="Center"><Button x:Name="btnOpenCloseCom" Margin="3" Width="80" Height="25" Click="btnOpenCloseCom_Click">打开串口</Button><Button x:Name="btnClearRecv" Margin="3" Width="80" Height="25" Click="btnClearRecv_Click">清空接收</Button></StackPanel></StackPanel></GroupBox><GroupBox Header="接收数据" MinWidth="590" MaxWidth="1000"><ScrollViewer><ScrollViewer.Content><TextBlock x:Name="textBlockRecv" MinWidth="300" MaxWidth="1000"></TextBlock></ScrollViewer.Content></ScrollViewer></GroupBox></StackPanel></TabItem><TabItem><TabItem.Header><StackPanel><Label>数据读取</Label></StackPanel></TabItem.Header><StackPanel Orientation="Horizontal"><StackPanel Orientation="Vertical"><GroupBox Header="记录总数"><StackPanel Orientation="Vertical"><Button x:Name="btnReadRecCount" Margin="3" Padding="5" Click="btnReadRecCount_Click">读取记录总数</Button><StackPanel Orientation="Horizontal"><Label>报警记录总数:</Label><TextBox x:Name="txtBoxWarningCount">0</TextBox></StackPanel><StackPanel Orientation="Horizontal"><Label>报警恢复记录总数:</Label><TextBox x:Name="txtBoxWarningRecoveryCount">0</TextBox></StackPanel><StackPanel Orientation="Horizontal"><Label>故障记录总数:</Label><TextBox x:Name="txtBoxFaultCount">0</TextBox></StackPanel><StackPanel Orientation="Horizontal"><Label>故障恢复记录总数:</Label><TextBox x:Name="txtBoxFaultRecoryCount">0</TextBox></StackPanel><StackPanel Orientation="Horizontal"><Label>掉电记录总数:</Label><TextBox x:Name="txtBoxPoweroffCount">0</TextBox></StackPanel><StackPanel Orientation="Horizontal"><Label>上电记录总数:</Label><TextBox x:Name="txtBoxPoweronCount">0</TextBox></StackPanel><StackPanel Orientation="Horizontal"><Label>传感器失效记录总数:</Label><TextBox x:Name="txtSensorInvalidCount">0</TextBox></StackPanel></StackPanel></GroupBox><GroupBox Header="日期时间"><StackPanel Orientation="Vertical"><Button x:Name="btnReadDateTime" Click="btnReadDateTime_Click">读取日期时间</Button><TextBox x:Name="txtBoxDateTime">0000-00-00 00:00</TextBox></StackPanel></GroupBox></StackPanel><StackPanel Orientation="Vertical"><GroupBox Header="读取指定记录"><StackPanel Orientation="Horizontal"><ComboBox x:Name="cmboxRecordType" Width="120" SelectedIndex="0"><ComboBoxItem>报警记录</ComboBoxItem><ComboBoxItem>报警恢复记录</ComboBoxItem><ComboBoxItem>故障记录</ComboBoxItem><ComboBoxItem>故障恢复记录</ComboBoxItem><ComboBoxItem>掉电记录</ComboBoxItem><ComboBoxItem>上电记录</ComboBoxItem><ComboBoxItem>传感器失效记录</ComboBoxItem></ComboBox><TextBox x:Name="txtBoxNumber" Width="50">1</TextBox><Button x:Name="btnReadRecord" Click="btnReadRecord_Click" ClickMode="Press">读取记录</Button><TextBox x:Name="txtBoxRecordInfo">0000/00/00  00:00</TextBox></StackPanel></GroupBox></StackPanel></StackPanel></TabItem></TabControl></Grid>
</Window>

代码文件

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;namespace GasAlarmTestTool
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{private int warningCnt = 0;private int warningRecoveryCnt = 0;private int faultCnt = 0;private int faultRecoveryCnt = 0;private int poweroffCnt = 0;private int poweronCnt = 0;private int sensorInvalidCnt = 0;long recvTimems = 0;    // 用于计算串口接收完一帧数据int rxLen = 0;  // 串口接收到的数据长度byte[] rxBuff = new byte[128];  // 串口数据接收缓存private static Timer mTimer;    // 定时器,10ms执行一次SerialPort mSerialPort = new SerialPort(); private StringBuilder lineBuilder = new StringBuilder();    // 用于存放串口接收数据private List<string> baudrateList = new List<string> { "4800", "9600", "19200","38400","57600","115200","256000","1000000","2000000","3000000"};public MainWindow(){InitializeComponent();// 获取所有可用串口端口,并添加到comboBoxCOMstring[] ports = System.IO.Ports.SerialPort.GetPortNames();comboBoxCOM.ItemsSource = ports;comboBoxCOM.SelectedIndex = 0;  // 默认选择索引comboBoxBaudRate.ItemsSource = baudrateList;    // 波特率设置combobox数据源mTimer = new Timer(recvTimerCalback, null, 0, 10);  // 创建并启动定时器}/// <summary>/// 窗口关闭处理/// </summary>/// <param name="e"></param>protected override void OnClosing(System.ComponentModel.CancelEventArgs e){            if (MessageBox.Show("确定要退出吗?", "确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes){// 用户选择“否”,取消关闭e.Cancel = true;}mSerialPort.Close();mTimer.Dispose();base.OnClosing(e);}private string RecordInfoString(byte[] buf){if (buf.Length < 11) {return "";}int index = buf[4];int year = buf[5] << 8 | buf[6];int month = buf[7];int day = buf[8];int hour = buf[9];int minute = buf[10];return  year.ToString() + "/" + month.ToString() + "/" + day.ToString() + "   " + hour.ToString() + ":" + minute.ToString();            }/// <summary>/// 串口接收处理定时器回调/// </summary>/// <param name="obj"></param>private void recvTimerCalback(object obj){//Console.WriteLine("timer callback!" + recvTimems);this.Dispatcher.Invoke(new Action(()=> {// UI线程分离,更新UI数据显示if (((Environment.TickCount - recvTimems) >= 20) && (rxLen > 0)){// 串口接收时间超过X ms认为一帧数据接收完成uint HEAD = rxBuff[0];uint C1 = rxBuff[1];uint C2 = rxBuff[2];uint L = rxBuff[3];uint CS = rxBuff[L + 4];uint END = rxBuff[L + 5];// 打印串口结束缓存数据uint _CS = 0;   // 计算接收数据校验和uint index = 0;UInt32 temp = 0;for (int i = 0; i < rxLen; i++){if (i < (rxLen - 2)){temp += rxBuff[i];}Console.WriteLine(rxBuff[i].ToString("X2"));}_CS = (uint)(temp % 0xFF);if ((0xAA == rxBuff[0]) && (0x55 == END)){// TODO: 接收到一帧完整数据Console.WriteLine("RS232 RECV ONE FRAME!" + CS.ToString("X2") + ", " + _CS.ToString("X2"));if (CS == _CS){// TODO: CHECKSUM8 校验和正确Console.WriteLine("CheckSum OK");if (0x00 == C2){if (0x00 == C1){// TODO: 查询各类记录总数warningCnt = rxBuff[4]; // 探测器报警记录总数warningRecoveryCnt = rxBuff[5]; // 探测器报警恢复记录总数faultCnt = rxBuff[6];   // 探测器故障记录总数faultRecoveryCnt = rxBuff[7]; // 探测器故障恢复记录总数poweroffCnt = rxBuff[8];    // 探测器掉电记录总数poweronCnt = rxBuff[9];     // 探测器上电记录总数sensorInvalidCnt = rxBuff[10];  // 传感器失效记录总数txtBoxWarningCount.Text = warningCnt.ToString();txtBoxWarningRecoveryCount.Text = warningRecoveryCnt.ToString();txtBoxFaultCount.Text = faultCnt.ToString();txtBoxFaultRecoryCount.Text = faultRecoveryCnt.ToString();txtBoxPoweroffCount.Text = poweroffCnt.ToString();  txtBoxPoweronCount.Text = poweronCnt.ToString();}}else if (0x01 == C2){// 报警记录txtBoxRecordInfo.Text = RecordInfoString(rxBuff);}else if (0x02 == C2){// 报警恢复记录txtBoxRecordInfo.Text = RecordInfoString(rxBuff);}else if (0x03 == C2){// 故障记录txtBoxRecordInfo.Text = RecordInfoString(rxBuff);}else if (0x04 == C2){// 故障恢复记录txtBoxRecordInfo.Text = RecordInfoString(rxBuff);}else if (0x05 == C2){// 掉电记录txtBoxRecordInfo.Text = RecordInfoString(rxBuff);}else if (0x06 == C2){// 上电记录txtBoxRecordInfo.Text = RecordInfoString(rxBuff);}else if (0x07 == C2){// 传感器失效记录txtBoxRecordInfo.Text = RecordInfoString(rxBuff);}else if (0x08 == C2){// TODO: 日期时间int year = rxBuff[4] << 8 | rxBuff[5];int month = rxBuff[6];int day = rxBuff[7];int hour = rxBuff[8];int minute = rxBuff[9];txtBoxDateTime.Text = year.ToString() + "/" + month.ToString() + "/" + day.ToString() + "   "+hour.ToString() + ":"+minute.ToString();                                }}else{// TODO: CHECKSUM8 校验和有误Console.WriteLine("CheckSum ERR");}}Array.Clear(rxBuff, 0, rxBuff.Length);rxLen = 0;}}));                        }/// <summary>/// 串口数据接收函数/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e){SerialPort comPort = (SerialPort)sender;try{recvTimems = Environment.TickCount; // 更新串口数据接收时间//rxBuff[rxLen] = mSerialPort.ReadByte();int readCnt = mSerialPort.BytesToRead;Console.WriteLine("in readCnt:" + readCnt);mSerialPort.Read(rxBuff, rxLen, readCnt);rxLen += readCnt;Console.WriteLine("out rxLen:" + rxLen);#if falsebyte[] data = new byte[mSerialPort.BytesToRead];mSerialPort.Read(data, 0, data.Length);Console.WriteLine(data.Length);foreach (byte b in data){ Console.WriteLine(b.ToString("X2"));                    }
#endif}catch (Exception ce){MessageBox.Show(ce.Message);}            }private void btnOpenCloseCom_Click(object sender, RoutedEventArgs e){if (mSerialPort.IsOpen){mSerialPort.Close();btnOpenCloseCom.Content = "打开串口";Console.WriteLine("关闭串口成功");Debug.WriteLine("关闭串口成功");comboBoxBaudRate.IsEnabled = true;comboBoxCOM.IsEnabled = true;comboBoxDataBit.IsEnabled = true;comboBoxStopBit.IsEnabled = true;comboBoxSdd.IsEnabled = true;comboBoxlik.IsEnabled = true;}else{mSerialPort.PortName = comboBoxCOM.SelectedItem.ToString();mSerialPort.BaudRate = 4800; // 波特率mSerialPort.DataBits = 8;   // 数据位mSerialPort.StopBits = StopBits.One;    // 停止位mSerialPort.Parity = Parity.None;   // 校验位mSerialPort.Handshake = Handshake.None;//mSerialPort.ReadTimeout = 1500; // 读超时//mSerialPort.Encoding = Encoding.UTF8; // 编码方式//mSerialPort.RtsEnable = true;mSerialPort.DataReceived += SerialPort_DataReceived;Console.WriteLine("baudrate SelectedIndex:" + comboBoxBaudRate.SelectedIndex);Console.WriteLine("baudrate SelectedValue:" + comboBoxBaudRate.SelectedValue);Console.WriteLine("baudrate Text:" + comboBoxBaudRate.Text);if (comboBoxBaudRate.SelectedIndex < 0){mSerialPort.BaudRate = Convert.ToInt32(comboBoxBaudRate.Text);}else {switch (comboBoxBaudRate.SelectedValue){case "4800":mSerialPort.BaudRate = 4800;break;case "9600":mSerialPort.BaudRate = 9600;break;case "19200":mSerialPort.BaudRate = 19200;break;case "38400":mSerialPort.BaudRate = 38400;break;case "57600":mSerialPort.BaudRate = 57600;break;case "115200":mSerialPort.BaudRate = 115200;break;case "256000":mSerialPort.BaudRate = 256000;break;case "1000000":mSerialPort.BaudRate = 1000000;break;case "2000000":mSerialPort.BaudRate = 2000000;break;case "3000000":mSerialPort.BaudRate = 3000000;break;                       default:MessageBox.Show("波特率设置有误!");break;}}Console.WriteLine("端口:" + mSerialPort.PortName  + ",波特率:" + mSerialPort.BaudRate);// mSerialPort.Write("Hello world"); // 写字符串口// mSerialPort.Write(new byte[] { 0xA0, 0xB0, 0xC0}, 0, 3); // 写入3个字节数据//Debug.WriteLine("Hello world");//MessageBox.Show("端口名:" + mSerialPort.PortName);try{mSerialPort.Open();btnOpenCloseCom.Content = "关闭串口";Console.WriteLine("打开串口成功");Debug.WriteLine("打开串口成功");comboBoxBaudRate.IsEnabled = false;comboBoxCOM.IsEnabled = false;comboBoxDataBit.IsEnabled = false;comboBoxStopBit.IsEnabled = false;comboBoxSdd.IsEnabled = false;comboBoxlik.IsEnabled = false;}catch (Exception ex){MessageBox.Show(ex.Message);}}}private void btnClearRecv_Click(object sender, RoutedEventArgs e){lineBuilder.Clear();textBlockRecv.Text = lineBuilder.ToString();}private void comboBoxCOM_Drop(object sender, DragEventArgs e){string[] ports = System.IO.Ports.SerialPort.GetPortNames();comboBoxCOM.ItemsSource = ports;comboBoxCOM.SelectedIndex = 0;}private void comboBoxBaudRate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e){ComboBoxItem obj = (ComboBoxItem)sender;}private void btnReadRecCount_Click(object sender, RoutedEventArgs e){if (mSerialPort.IsOpen){mSerialPort.Write(new byte[] { 0xAA, 0x00, 0x00, 0x00, 0xAA, 0x55 }, 0, 6); // 写入3个字节数据         }else{MessageBox.Show("请先打开串口!");}}private void btnReadDateTime_Click(object sender, RoutedEventArgs e){if (mSerialPort.IsOpen){mSerialPort.Write(new byte[] { 0xAA, 0x00, 0x08, 0x00, 0xB2, 0x55 }, 0, 6);}else{MessageBox.Show("请先打开串口!");}}private void btnReadRecord_Click(object sender, RoutedEventArgs e){            int index = Convert.ToInt32(txtBoxNumber.Text);if (index < 1 || index > 255){MessageBox.Show("记录索引:1~255!");}else {byte C1 = (byte)Convert.ToInt32(txtBoxNumber.Text);byte C2 = (byte)(cmboxRecordType.SelectedIndex);byte CS = (byte)((0xAA + C1 + C2)%0xFF);if (mSerialPort.IsOpen){byte[] Data = new byte[16];Data[0] = 0xAA;Data[1] = C1;   // 指定记录条数Data[2] = (byte)(C2 + 1);   // C2 记录分类从1开始Data[3] = 0x00;Data[4] = CS;Data[5] = 0x55;mSerialPort.Write(Data, 0, 6);}else{MessageBox.Show("请先打开串口!");}}}}
}

运行效果

在这里插入图片描述
在这里插入图片描述

源码下载

下载源码

这篇关于C# WPF燃气报警器记录读取串口工具的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1143402

相关文章

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

c# checked和unchecked关键字的使用

《c#checked和unchecked关键字的使用》C#中的checked关键字用于启用整数运算的溢出检查,可以捕获并抛出System.OverflowException异常,而unchecked... 目录在 C# 中,checked 关键字用于启用整数运算的溢出检查。默认情况下,C# 的整数运算不会自

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如

C#中图片如何自适应pictureBox大小

《C#中图片如何自适应pictureBox大小》文章描述了如何在C#中实现图片自适应pictureBox大小,并展示修改前后的效果,修改步骤包括两步,作者分享了个人经验,希望对大家有所帮助... 目录C#图片自适应pictureBox大小编程修改步骤总结C#图片自适应pictureBox大小上图中“z轴

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如