2026-01-21 09:50:58 +08:00

824 lines
33 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using MQTT_WinformV1.Model;
using MqttClient;
using MySqlX.XDevAPI.Relational;
using Newtonsoft.Json;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace MQTT_WinformV1
{
public partial class Form1 : Form
{
private System.Timers.Timer _timer;
private MqttClientService _mqttService;
private DataTable dtPeiFang;
private DataTable dtMqttDic;
private string strPeiFangId1;
private DataRow drPeiFang1;
private string strPeiFangId2;
private DataRow drPeiFang2;
// 日志文件相关路径
private string _logDirectory = "log";
private string _currentLogFile;
private DateTime _lastLogDate = DateTime.MinValue;
private List<DataRow> drPeiFang1List; // 设备1选择的配方多行
private List<DataRow> drPeiFang2List; // 设备2选择的配方多行
public Form1()
{
InitializeComponent();
_mqttService = new MqttClientService();
_mqttService.MessageReceived += OnMqttMessage;
dtPeiFang = new DataTable();
dtMqttDic = new DataTable();
buttonDisconnect.Enabled = false;
// 初始化日志目录
InitializeLogDirectory();
}
/// <summary>
/// 初始化日志目录
/// </summary>
private void InitializeLogDirectory()
{
if (!Directory.Exists(_logDirectory))
{
Directory.CreateDirectory(_logDirectory);
}
UpdateLogFile();
}
/// <summary>
/// 更新当前日志文件(每日一个新文件)
/// </summary>
private void UpdateLogFile()
{
DateTime today = DateTime.Now.Date;
if (today != _lastLogDate)
{
_lastLogDate = today;
_currentLogFile = Path.Combine(_logDirectory, $"log_{today:yyyyMMdd}.txt");
}
}
private void Form1_Load(object sender, EventArgs e)
{
// 调用方法将指定 Panel 变成圆形
MakePanelRound(panelLed);
getPeiFang();
InitMqttDic();//查询字典表为dtMqttDic赋值。
timer1.Enabled = true;
}
private void MakePanelRound(Panel panel)
{
int size = Math.Min(panel.Width, panel.Height);
panel.Size = new Size(size, size);
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, panel.Width, panel.Height);
panel.Region = new Region(path);
}
private async void getPeiFang()
{
//DataTable dt = await _mqttService.QueryPeifangAsync();//从数据库中查询配方信息
//if (dt != null)
//{
// DataRow drNew = dt.NewRow();//新建一个空白行NewRow()
// drNew["id"] = -1;//将空白行id设置为-1
// dt.Rows.InsertAt(drNew, 0);//将空白行插入到第 0 行,也就是数据源的第一行。
// // 新增一列用于组合显示“零件号+零件名”
// if (!dt.Columns.Contains("part_display"))
// {
// dt.Columns.Add("part_display", typeof(string));
// }
// foreach (DataRow row in dt.Rows)
// {
// string partNumber = row["part_number"]?.ToString() ?? "";
// string partName = row["part_name"]?.ToString() ?? "";
// row["part_display"] = $"{partNumber} {partName}";
// }
// dtPeiFang = dt;//得到新的配方表(多了第一行的空白行)
// bsPF.DataSource = dtPeiFang;//为bsPF设置数据源
// bsPF2.DataSource = dtPeiFang;//为bsPF2设置数据源
// this.comboBox1.DisplayMember = "part_name";//下拉框里显示part_name字段的值(零件名)
// this.comboBox1.ValueMember = "id";
// this.comboBox2.DisplayMember = "part_name";//下拉框里显示part_name字段的值(零件名)
// this.comboBox2.ValueMember = "id";
//}
DataTable dt = await _mqttService.QueryPeifangAsync(); // 从数据库查询配方信息
if (dt != null && dt.Rows.Count > 0)
{
// 新增列用于拼接 part_number|part_name
if (!dt.Columns.Contains("part_number_name"))
dt.Columns.Add("part_number_name", typeof(string));
foreach (DataRow row in dt.Rows)
{
row["part_number_name"] = row["part_number"].ToString() + "|" + row["part_name"].ToString();
}
// 使用 LINQ 去重,按 part_number + part_name
var uniqueParts = dt.AsEnumerable()
.GroupBy(r => r["part_number_name"].ToString())
.Select(g => g.First())
.ToList();
// 新建 DataTable 用于绑定下拉框
DataTable dtUnique = dt.Clone(); // 保留原有列
foreach (var row in uniqueParts)
{
dtUnique.ImportRow(row);
}
// 新建空白行
DataRow drNew = dtUnique.NewRow();
drNew["id"] = -1;
drNew["part_number_name"] = ""; // 空行值
dtUnique.Rows.InsertAt(drNew, 0);
dtPeiFang = dt; // 原始配方表(多行)
bsPF.DataSource = dtUnique;
bsPF2.DataSource = dtUnique;
comboBox1.DisplayMember = "part_number_name"; // 显示“零件号|零件名”
comboBox1.ValueMember = "part_number_name";
comboBox2.DisplayMember = "part_number_name";
comboBox2.ValueMember = "part_number_name";
// 自定义显示格式:显示“零件号 - 零件名”
comboBox1.Format += (s, e) =>
{
if (e.ListItem is DataRowView drv)
{
e.Value = string.IsNullOrEmpty(drv["part_number_name"].ToString()) ? "" :
drv["part_number"].ToString() + " - " + drv["part_name"].ToString();
}
};
comboBox2.Format += (s, e) =>
{
if (e.ListItem is DataRowView drv)
{
e.Value = string.IsNullOrEmpty(drv["part_number_name"].ToString()) ? "" :
drv["part_number"].ToString() + " - " + drv["part_name"].ToString();
}
};
}
}
//初始化MQTT字典
private async void InitMqttDic()
{
DataTable dt = await _mqttService.InitMqttDic();
if (dt != null)
{
dtMqttDic = dt;
}
}
private async void buttonConnect_Click(object sender, EventArgs e)
{
try
{
AppendLog("正在连接MQTT服务器...");
await _mqttService.MqttClientStartAsync();
AppendLog("连接成功!");
panelLed.BackColor = Color.Green;
toolStripStatusLabel1.Text = "已连接";
buttonConnect.Enabled = false;
buttonDisconnect.Enabled = true;
}
catch (Exception ex)
{
panelLed.BackColor = Color.Red;
AppendLog($"连接失败:{ex.Message}");
toolStripStatusLabel1.Text = "连接失败";
}
}
private async void buttonDisconnect_Click(object sender, EventArgs e)
{
await _mqttService.MqttClientStopAsync();
AppendLog("已断开连接。");
panelLed.BackColor = Color.Red;
toolStripStatusLabel1.Text = "未连接";
buttonConnect.Enabled = true;
buttonDisconnect.Enabled = false;
}
private void OnMqttMessage(string msg)
{
if (InvokeRequired)
{
BeginInvoke(new Action<string>(OnMqttMessage), msg);
return;
}
AppendLog($"收到消息: {msg}");
}
//public void AppendLog(string message)
//{
// try
// {
// if (InvokeRequired)
// {
// BeginInvoke(new Action<string>(AppendLog), message);
// return;
// }
// string timeStamped = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}\r\n";
// textBoxLog.AppendText(timeStamped);
// }
// catch (Exception ex)
// {
// }
//}
/// <summary>
/// 写入日志到文本框并保存到文件
/// </summary>
public void AppendLog(string message)
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action<string>(AppendLog), message);
return;
}
// 格式化带时间戳的日志
string timeStamped = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}\r\n";
// 保存到日志文件
SaveToLogFile(timeStamped);
// 添加到文本框并限制行数
textBoxLog.AppendText(timeStamped);
LimitLogLines(500);
}
catch (Exception ex)
{
// 可以在这里添加错误处理,例如写入错误日志
// MessageBox.Show($"日志处理错误: {ex.Message}");
}
}
/// <summary>
/// 将日志保存到文件
/// </summary>
private void SaveToLogFile(string logContent)
{
try
{
UpdateLogFile(); // 确保使用当天的日志文件
// 追加写入日志使用UTF8编码避免中文乱码
File.AppendAllText(_currentLogFile, logContent, System.Text.Encoding.UTF8);
}
catch (Exception ex)
{
// 文件写入错误处理
// MessageBox.Show($"日志文件写入错误: {ex.Message}");
}
}
/// <summary>
/// 限制日志文本框的最大行数
/// </summary>
private void LimitLogLines(int maxLines)
{
// 按换行符分割所有行
string[] lines = textBoxLog.Text.Split(new[] { "\r\n" }, StringSplitOptions.None);
// 如果超过最大行数只保留最后maxLines行
if (lines.Length > maxLines)
{
// 计算需要保留的起始索引
int startIndex = lines.Length - maxLines;
string[] newLines = new string[maxLines];
Array.Copy(lines, startIndex, newLines, 0, maxLines);
// 重新设置文本框内容并保持滚动到最底部
textBoxLog.Text = string.Join("\r\n", newLines);
// 滚动到最新内容
textBoxLog.SelectionStart = textBoxLog.TextLength;
textBoxLog.ScrollToCaret();
}
else
{
// 未超过限制时也滚动到最底部
textBoxLog.SelectionStart = textBoxLog.TextLength;
textBoxLog.ScrollToCaret();
}
}
private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
await _mqttService.MqttClientStopAsync();
}
//配方导入功能
private async void button1_Click(object sender, EventArgs e)
{
try
{
//弹出文件选择窗口
OpenFileDialog openFile = new OpenFileDialog();
if (openFile.ShowDialog() == DialogResult.OK)
{
string filePath = openFile.FileName;
DataTable excelDt = GetExcel(filePath);
if (excelDt != null && excelDt.Rows.Count > 0)
{
await _mqttService.SavePeiFangByExcel(excelDt);
getPeiFang();
MessageBox.Show("配方信息已导入!");
}
else
{
MessageBox.Show("不允许导入空表!");
}
}
}
catch (Exception ex)
{
AppendLog($"配方导入失败:{ex.Message}");
}
}
// <summary>
/// 获取Excel到Datatable中
/// </summary>
/// <param name="filePath">Excel路径</param>
/// <returns>返回DataTable数据</returns>
public static DataTable GetExcel(string filePath)
{
IWorkbook iwkX;
using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
iwkX = WorkbookFactory.Create(fs);
fs.Close();
}
//sheet
DataTable dt = new DataTable();
for (int h = 0; h < iwkX.NumberOfSheets; h++)
{
ISheet sheet = iwkX.GetSheetAt(h);
var rows = sheet.GetRowEnumerator();
bool isMove = rows.MoveNext();
//循环sheet
if (isMove)
{
var Cols = (IRow)rows.Current;
dt.TableName = sheet.SheetName;
for (int i = 0; i < Cols.LastCellNum; i++)
{
string str = Cols.GetCell(i).ToString();
dt.Columns.Add(Cols.GetCell(i).ToString());
}
while (rows.MoveNext())
{
var row = (IRow)rows.Current;
var dr = dt.NewRow();
for (int i = 0; i < row.LastCellNum; i++)
{
var cell = row.GetCell(i);
if (cell == null)
{
dr[i] = "";
}
else
{
string strdr = cell.ToString();
dr[i] = cell.ToString();
}
}
dt.Rows.Add(dr);
}
}
}
return dt;
}
//上传宜搭
private async void button2_Click(object sender, EventArgs e)
{
try
{
if (toolStripStatusLabel1.Text != "已连接")//如果 MQTT 没连接,就不允许上传。
{
MessageBox.Show("请先连接MQTT网关");
return;
}
if (this.comboBox1.Text.Length == 0 && this.comboBox2.Text.Length == 0)
{//如果两个下拉框都还没数据,说明没导入过配方,直接中止。
MessageBox.Show("请先导入配方信息,再刷新!");
return;
}
this.button2.Enabled = false;
////取出设备1选择的配方IDValueMember="id"
////在配方表 dtPeiFang 中找到那一行的完整记录,赋值给 drPeiFang1这里是通过SelectedValue
//strPeiFangId1 = this.comboBox1.SelectedValue.ToString();
//drPeiFang1 = dtPeiFang.Select("id = '" + strPeiFangId1 + "'")[0];
////判断是否选了“空选项”,选了这个空项,程序会清空对应的配方引用。
//if (strPeiFangId1 == "-1")
//{
// strPeiFangId1 = "";
// drPeiFang1 = null;
//}
// 设备1选择配方
string selected1 = this.comboBox1.SelectedValue?.ToString();
if (string.IsNullOrEmpty(selected1) || selected1 == "-1")
{
drPeiFang1List = null;
}
else
{
string[] arr1 = selected1.Split('|');
if (arr1.Length == 2)
{
string partNumber1 = arr1[0];
string partName1 = arr1[1];
drPeiFang1List = dtPeiFang.AsEnumerable()
.Where(r => r.Field<string>("part_number") == partNumber1
&& r.Field<string>("part_name") == partName1)
.ToList();
}
else
{
drPeiFang1List = null;
}
}
//strPeiFangId2 = this.comboBox2.SelectedValue.ToString();
//drPeiFang2 = dtPeiFang.Select("id = '" + strPeiFangId2 + "'")[0];
//if (strPeiFangId2 == "-1")
//{
// strPeiFangId2 = "";
// drPeiFang2 = null;
//}
// 设备2选择配方
string selected2 = this.comboBox2.SelectedValue?.ToString();
if (string.IsNullOrEmpty(selected2) || selected2 == "-1")
{
drPeiFang2List = null;
}
else
{
string[] arr2 = selected2.Split('|');
if (arr2.Length == 2)
{
string partNumber2 = arr2[0];
string partName2 = arr2[1];
drPeiFang2List = dtPeiFang.AsEnumerable()
.Where(r => r.Field<string>("part_number") == partNumber2
&& r.Field<string>("part_name") == partName2)
.ToList();
}
else
{
drPeiFang2List = null;
}
}
double seconds;
if (!double.TryParse(txtLUploadPL.Text, out seconds) || seconds <= 0)
{
seconds = 10;//控制上传间隔默认10秒。
}
// 立即上传一次
await MQttYiDaUpload();
_timer = new System.Timers.Timer(seconds * 1000);
_timer.Elapsed += async (s, evt) =>
{
await MQttYiDaUpload();
};
_timer.AutoReset = true; // 是否重复
_timer.Enabled = true; // 开始计时
}
catch (Exception ex)
{
this.button2.Enabled = true;
AppendLog($"上传宜搭失败:{ex.Message}");
}
}
private void _timer_Tick(object sender, ElapsedEventArgs e)
{
MQttYiDaUpload();
AppendLog("宜搭数据已上传!");
}
//上传宜搭
private async Task MQttYiDaUpload()
{
//获取最新的2台设备数据各取最新1条。
DataTable dtMqtt = await _mqttService.GetLatestMqttDataAsync();
if (dtMqtt != null && dtMqtt.Rows.Count > 0)//有设备数据才会执行
{
foreach (DataRow dr in dtMqtt.Rows)//遍历dtMqtt中数据一行代表一个设备的数据一共2行
{
//DataRow drPeiFang = null;//先将drPeiFang设为空
//if (dr["device_code"].ToString() == "device1")//如果是设备1的数据
//{
// if (strPeiFangId1.Length > 0 && drPeiFang1 != null)//如果设备1选择了配方
// {
// drPeiFang = drPeiFang1;//drPeiFang的数据来源于drPeiFang1
// }
//}
//else if (dr["device_code"].ToString() == "device2")//如果是设备2的数据
//{
// if (strPeiFangId2.Length > 0 && drPeiFang2 != null)//如果设备2选择了配方
// {
// drPeiFang = drPeiFang2;//drPeiFang的数据来源于drPeiFang2
// }
//}
List<DataRow> drPeiFangList = null;
string site = null;
if (dr["device_code"].ToString() == "device1")
{
drPeiFangList = drPeiFang1List;
site = "1号设备";
}
else if (dr["device_code"].ToString() == "device2")
{
drPeiFangList = drPeiFang2List;
site = "2号设备";
}
////如果drPeiFang为空说明设备1或者设备2没有选择配方不需要将数据上传至宜搭平台结束本轮循环
//if (drPeiFang == null)
//{
// continue;
//}
if (drPeiFangList == null || drPeiFangList.Count == 0) continue;
//取出一条字段 MESSAGE
string strMessage = dr["MESSAGE"].ToString();
//反序列化设备收到的数据,取出里面的参数(@params。根据MqttDataModel 的定义。
MqttDataModel data = JsonConvert.DeserializeObject<MqttDataModel>(strMessage);
//如果反序列化失败或 params 为空,就跳过。
if (data == null || data.@params == null)
{
continue;
}
//获取 @params 的实际类型。
Type paramsType = data.@params.GetType();
//properties—>paramsType 的所有字段信息,[Value01, Value02, …, Value10]。
PropertyInfo[] properties = paramsType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
List<MQTTModel> mqttLists = new List<MQTTModel>();
List<YIDAModel> yidaLists = new List<YIDAModel>();
//遍历参数构造数据项
foreach (PropertyInfo prop in properties)
{
//parameter_name,参数名,比如 "Value01"
string name = prop.Name;
//parameter_value参数值,比如 24.6
object value = prop.GetValue(data.@params);
// 跳过空值null 或 ""
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
{
continue;
}
//查映射表
//如果找到了映射,就替换 name 为中文显示名,
//dtMqttDic在Form1_Load方法中已经被赋值是字典表中的数据。
DataRow[] drs = dtMqttDic.Select("col_code = '" + name + "'");
if (drs != null && drs.Length > 0)
{
name = drs[0]["name"].ToString();
}
DataRow drMatch = drPeiFangList.FirstOrDefault(r => r.Field<string>("parameter_name") == name);
if (drMatch == null) continue; // 没找到匹配行就跳过
//构造 MQTTModel用于存数据库
MQTTModel mqttNew = new MQTTModel();
//把当前参数数据与选中的配方信息drPeiFang融合形成一个完整记录。
mqttNew.SupplierCode = drMatch["supplier_code"].ToString();//供应商代码
mqttNew.SupplierName = drMatch["supplier_name"].ToString();//供应商名称
mqttNew.VehicleModel = drMatch["vehicle_model"].ToString();//车型
mqttNew.PartNumber = drMatch["part_number"].ToString();//零件号
mqttNew.PartName = drMatch["part_name"].ToString();//零件名
mqttNew.ParameterName = name;//parameter_name,参数名
mqttNew.ParameterValue = value == null ? "" : value.ToString();//parameter_value参数值
mqttNew.ToleranceLower = drMatch["tolerance_lower"].ToString();//下公差
mqttNew.ToleranceUpper = drMatch["tolerance_upper"].ToString();//上公差
mqttNew.LeaderPart = drMatch["leader_part"].ToString();//零件负责人
mqttNew.WorkStation = site;//工位
mqttNew.LeaderOutProtection = drMatch["leader_out_protection"].ToString();//外保负责人
//构造 YIDAModel用于宜搭上传
//把当前参数数据与选中的配方信息drPeiFang融合形成一个完整记录。
YIDAModel yidaNew = new YIDAModel();
yidaNew.textField_mha98neu = drMatch["supplier_code"].ToString();//供应商代码
yidaNew.textField_mha98nev = drMatch["supplier_name"].ToString();//供应商名称
yidaNew.textField_mha98new = drMatch["vehicle_model"].ToString();//车型
yidaNew.textField_mha98nex = drMatch["part_number"].ToString();//零件号
yidaNew.textField_mha98ney = drMatch["part_name"].ToString();//零件名
yidaNew.textField_mha98nf1 = name;//parameter_name,参数名
yidaNew.textField_mhx44i2i = value == null ? "" : value.ToString();//parameter_value参数值
yidaNew.textField_mhx44i2j = drMatch["tolerance_lower"].ToString();//下公差
yidaNew.textField_mhx44i2k = drMatch["tolerance_upper"].ToString();//上公差
yidaNew.textField_mha98nf7 = drMatch["leader_part"].ToString();//零件负责人
yidaNew.textField_mha98nf0 = site; //工位
yidaNew.textField_mha98nfh = drMatch["leader_out_protection"].ToString(); //外保负责人
//新增合格判断逻辑代码
if (name == "报警信息")
{
if (string.Equals(value?.ToString(), "无错误", StringComparison.Ordinal))
{
mqttNew.IsQualification = "合格";
yidaNew.textField_mha98nf5 = "合格";
}
else
{
mqttNew.IsQualification = "不合格";
yidaNew.textField_mha98nf5 = "不合格";
}
}
else if (name == "开模总数实时" || name == "托模次数")
{
mqttNew.IsQualification = "合格";
yidaNew.textField_mha98nf5 = "合格";
}
else
{
// 关键修正用参数值value比较而非参数名name
// 安全转换参数值、下公差、上公差为float
if (float.TryParse(value?.ToString(), out float paramValue) &&
float.TryParse(drMatch["tolerance_lower"].ToString(), out float toleranceLower) &&
float.TryParse(drMatch["tolerance_upper"].ToString(), out float toleranceUpper))
{
// 数值在公差范围内则合格
if (paramValue >= toleranceLower && paramValue <= toleranceUpper)
{
mqttNew.IsQualification = "合格";
yidaNew.textField_mha98nf5 = "合格";
}
else
{
mqttNew.IsQualification = "不合格";
yidaNew.textField_mha98nf5 = "不合格";
}
}
else
{
// 转换失败(如参数值非数值、公差为空),判定为不合格或跳过
mqttNew.IsQualification = "不合格";
yidaNew.textField_mha98nf5 = "不合格";
// 可选:输出日志排查转换失败的字段
this.AppendLog($"数值转换失败:参数名={name},参数值={value},下公差={drMatch["tolerance_lower"]},上公差={drMatch["tolerance_upper"]}");
}
}
mqttLists.Add(mqttNew);
yidaLists.Add(yidaNew);
}
int len = Math.Min(mqttLists.Count, yidaLists.Count);
if (len > 0)
{
List<MQTTModel> mqttLists1 = mqttLists.Take(len).ToList();
List<YIDAModel> yidaLists1 = yidaLists.Take(len).ToList();
string token = MqttClientService.GetDingDingToken();
if (string.IsNullOrEmpty(token))
{
MessageBox.Show("获取 token 失败,请检查 AppKey/AppSecret");
return;
}
MqttClientService.UploadDatabaseDataToYidaWithLogging(token, yidaLists1, mqttLists1, this);
}
//List<MQTTModel> mqttLists1 = mqttLists;
//List<YIDAModel> yidaLists1 = yidaLists;
//// 融合
//// 获取钉钉 token
//string token = MqttClientService.GetDingDingToken();
//if (string.IsNullOrEmpty(token))
//{
// MessageBox.Show("获取 token 失败,请检查 AppKey/AppSecret");
// return;
//}
//// 上传数据库数据到宜搭
//MqttClientService.UploadDatabaseDataToYidaWithLogging(token, yidaLists1, mqttLists1, this);
//if (result)
// MessageBox.Show("数据上传宜搭成功!");
//else
// MessageBox.Show("部分数据上传失败,请查看日志。");
////记载宜搭上传成功日志
//_mqttService.RecordSuccessLog(mqttLists1);
}
}
}
private void btnRefresh_Click(object sender, EventArgs e)
{
getPeiFang();
}
//中止上传
private void button3_Click(object sender, EventArgs e)
{
this.button2.Enabled = true;
if (this._timer != null)
{
this._timer.Enabled = false;
}
AppendLog("停止上传数据");
MessageBox.Show("待程序完成后,将停止自动上传", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void txtLUploadPL_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Back)
{
e.Handled = false;
return;
}
if (char.IsDigit(e.KeyChar))
{
e.Handled = false;
}
else if (e.KeyChar == '.' && !txtLUploadPL.Text.Contains("."))
{
e.Handled = false;
}
else
{
e.Handled = true;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
// 每秒更新一次时间显示
this.label4.Text = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}