using MV485.Dlg;
using MV485.helper;
using MV485.model;
using MV485.util;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
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;
using Path = System.IO.Path;
namespace MV485.uc
{
///
/// UCDeviceFinder.xaml 的交互逻辑
///
public partial class UCDeviceFinder : UserControl
{
private static readonly string LogFilePath =
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Documents", "search_log.txt");
private FindDeviceHelper _deviceFinder;
private List _logEntries = new List();
private bool _isSearching = false; // 记录搜索状态
//已找到的结果
//private List _findDevices = new List();
private ObservableCollection _findDevices { get; set; }
private DlgSearchDevices _dlgSearch;
public UCDeviceFinder()
{
InitializeComponent();
LoadSerialPorts();
LoadBaudrates();
LoadDevIdRange();
LoadTimeoutPer(); //每设备超时时间
LoadConfigLog(); //加载原来的日志
//指定搜索结果的数据源
_findDevices = new ObservableCollection();
lvResult.ItemsSource = _findDevices;
_deviceFinder = new FindDeviceHelper();
_deviceFinder.SearchFinished += OnSearchFinished;
_deviceFinder.SearchDevice += _deviceFinder_SearchDevice;
_deviceFinder.SearchLog += _deviceFinder_SearchLog;
_deviceFinder.SerialConnected += _deviceFinder_SerialConnected;
_deviceFinder.SerialStatusChanged += _deviceFinder_SerialStatusChanged;
if(bool.TryParse(ConfigManager.Instance.GetConfigValue(ConfigKey.IsSearchOne, "True"),out bool blSearchOne))
{
chkSearchSingle.IsChecked = blSearchOne;
}
chkSearchSingle.Checked += (sender, e) =>
{
ConfigManager.Instance.UpdateConfig(ConfigKey.IsSearchOne, chkSearchSingle.IsChecked.GetValueOrDefault().ToString());
};
chkSearchSingle.Unchecked += (sender, e) =>
{
ConfigManager.Instance.UpdateConfig(ConfigKey.IsSearchOne, chkSearchSingle.IsChecked.GetValueOrDefault().ToString());
};
}
private void LoadSerialPorts()
{
Dispatcher.BeginInvoke(new Action(() => {
cmbPortNames.ItemsSource = SerialHelper.GetSerialPortsWithDetails();
if (cmbPortNames.Items.Count > 0)
cmbPortNames.SelectedIndex = 0;
var portName = ConfigManager.Instance.GetConfigValue(ConfigKey.ConfigPortName, "");
cmbPortNames.SelectedValue = portName;
}));
}
//加载备选的波特率
private void LoadBaudrates()
{
//mcmbBaudrate.SetItems(new string[] {
// "115200", "57600", "38400", "19200", "9600", "14400",
// "56000", "4800", "2400", "1200", "600", "300", "110"
//});
mcmbBaudrate.SetItems(SerialHelper.BaudRates);
//mcmbBaudrate.SetSelectedValues("115200,9600");
var baudrates = ConfigManager.Instance.GetConfigValue(ConfigKey.SearchBaudrate, "");
mcmbBaudrate.SetSelectedValues(baudrates);
}
//加载设备地址范围
private void LoadDevIdRange()
{
txtMinId.Text = "";
txtMaxId.Text = "";
var idRange = ConfigManager.Instance.GetConfigValue(ConfigKey.DevIdRange, null);
if (idRange != null)
{
// 使用 Split 分割字符串
string[] parts = idRange.Split(',');
// 确保分割后有两个元素
if (parts.Length == 2 && int.TryParse(parts[0], out int minId) && int.TryParse(parts[1], out int maxId))
{
// 成功转换为整数
//Console.WriteLine($"Min ID: {minId}, Max ID: {maxId}");
txtMinId.Text = minId.ToString();
txtMaxId.Text = maxId.ToString();
}
}//if
}
private void LoadTimeoutPer()
{
txtIdTimeout.Text = 100.ToString();
var timeout = ConfigManager.Instance.GetConfigValue(ConfigKey.SerachTimeoutPer, "100");
if(int.TryParse(timeout,out int iTimeout))
{
txtIdTimeout.Text = iTimeout.ToString();
}
}
private void btnSearch_Click(object sender, RoutedEventArgs e)
{
if (_isSearching)
{
StopSearch();
}
else
{
_findDevices.Clear();
StartSearch();
}
}
private async void StartSearch()
{
// MessageBox.Show(this, "这是一个消息框", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
if (cmbPortNames.SelectedItem == null)
{
MessageBox.Show(Application.Current.MainWindow,"请选择串口", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
var portName = cmbPortNames.SelectedValue.ToString();
ConfigManager.Instance.UpdateConfig(ConfigKey.ConfigPortName, portName);
//获取选中的波特率数据
string sBaudrates = mcmbBaudrate.GetSelectedItems();
if (string.IsNullOrEmpty(sBaudrates))
{
MessageBox.Show(Application.Current.MainWindow,"请选择要搜索的波特率","提示",MessageBoxButton.OK,MessageBoxImage.Warning);
return;
}
//保存选择的值
ConfigManager.Instance.UpdateConfig(ConfigKey.SearchBaudrate, sBaudrates);
if (!byte.TryParse(txtMinId.Text, out byte minId) ||
!byte.TryParse(txtMaxId.Text, out byte maxId) ||
minId < 0 || minId > 255 || maxId < 0 || maxId > 255 || minId > maxId)
{
MessageBox.Show(Application.Current.MainWindow, "请填入正确的地址范围","提示",MessageBoxButton.OK,MessageBoxImage.Warning);
return;
}
string idRanges = $"{minId},{maxId}";
//保存用户的选择
ConfigManager.Instance.UpdateConfig(ConfigKey.DevIdRange, idRanges);
if(!int.TryParse(txtIdTimeout.Text,out int iTimeout) || iTimeout < 10 || iTimeout > 1000)
{
MessageBox.Show(Application.Current.MainWindow, "请输入正确的超时时间(10-1000)ms", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
ConfigManager.Instance.UpdateConfig(ConfigKey.SerachTimeoutPer, iTimeout.ToString());
//string portName = cmbPortNames.SelectedValue.ToString();
//_deviceFinder = new FindDeviceHelper(portName);
//_deviceFinder.SearchFinished += OnSearchFinished;
//_deviceFinder.SearchDevice += _deviceFinder_SearchDevice;
//_deviceFinder.SearchLog += _deviceFinder_SearchLog;
//_deviceFinder.SerialConnected += _deviceFinder_SerialConnected;
//_deviceFinder.SerialStatusChanged += _deviceFinder_SerialStatusChanged;
_isSearching = true;
ChangeBtnSearchStatus(_isSearching);
//AppendLog("开始搜索设备,串口:" + portName);
//string titleInfo = "正在搜索设备...";
//WaitWindow waitWindow = new WaitWindow(titleInfo)
//{
// Owner = Application.Current.MainWindow,
// WindowStartupLocation = WindowStartupLocation.CenterOwner
//};
//waitWindow.Show();
_dlgSearch = new DlgSearchDevices()
{
Owner = Application.Current.MainWindow,
WindowStartupLocation = WindowStartupLocation.CenterOwner
};
_dlgSearch.OnStopTask += () =>
{
StopSearch();
};
_dlgSearch.Show();
Application.Current.MainWindow.IsEnabled = false;
try
{
bool blSearchOne = chkSearchSingle.IsChecked == true ? true : false;
await Task.Run(() => _deviceFinder.StartSearch(portName,sBaudrates, minId, maxId,blSearchOne));
}
catch { }
finally
{
//waitWindow.Close();
_dlgSearch?.Close();
Application.Current.MainWindow.IsEnabled = true;
string findCounMsg = _deviceFinder._findCount == 0 ?
"未搜索到设备" : $"已搜索到{_deviceFinder._findCount}台设备";
MessageBox.Show(Application.Current.MainWindow, findCounMsg, "提示",
MessageBoxButton.OK, MessageBoxImage.Information);
//StopSearch();
}
}
private void _deviceFinder_SerialStatusChanged(bool blStatus)
{
//throw new NotImplementedException();
}
private void _deviceFinder_SerialConnected(bool blConnected)
{
//throw new NotImplementedException();
}
private void StopSearch()
{
_deviceFinder?.StopSearch();
_isSearching = false;
ChangeBtnSearchStatus(_isSearching);
//AppendLog("搜索已停止");
}
private void btnRefreshPorts_Click(object sender, RoutedEventArgs e)
{
LoadSerialPorts();
AppendLog("串口列表已刷新");
}
private void btnClearLog_Click(object sender, RoutedEventArgs e)
{
_logEntries.Clear();
lvLogs.ItemsSource = null;
File.WriteAllText(LogFilePath, "");
AppendLog("日志已清空");
}
private void _deviceFinder_SearchDevice(string portName, int baudRate, byte deviceId)
{
Dispatcher.Invoke(() =>
{
AppendLog($"成功找到设备!波特率: {baudRate}, 设备ID: 0x{deviceId:X2}");
DeviceAddressItem device = new DeviceAddressItem()
{
PortName = portName,
BaudRate = baudRate,
DeviceAddress = deviceId
};
_findDevices.Add(device);
});
}
//private void OnSearchFinished(bool success, string portName, int baudRate, byte deviceId)
//{
// _deviceFinder?.Disponse();
// Dispatcher.Invoke(() =>
// {
// _isSearching = false;
// ChangeBtnSearchStatus(_isSearching);
// if (success)
// {
// txtResult.Text = $"设备找到!串口: {portName}, 波特率: {baudRate}, 设备ID: 0x{deviceId:X2}";
// txtResult.Foreground = System.Windows.Media.Brushes.Green;
// AppendLog($"成功找到设备!波特率: {baudRate}, 设备ID: 0x{deviceId:X2}");
// DeviceAddressItem device = new DeviceAddressItem()
// {
// PortName = portName,
// BaudRate = baudRate,
// DeviceAddress = deviceId
// };
// _findDevices.Add(device);
// //lvResult.ItemsSource = null;
// //lvResult.ItemsSource = _findDevices;
// }
// else
// {
// txtResult.Text = "未找到设备";
// txtResult.Foreground = System.Windows.Media.Brushes.Red;
// AppendLog("搜索失败,未找到设备");
// }
// });
//}
private void OnSearchFinished(int findCount)
{
_deviceFinder?.Disponse();
Dispatcher.Invoke(() =>
{
_isSearching = false;
ChangeBtnSearchStatus(_isSearching);
AppendLog($"本次搜索找到{findCount}台设备");
});
}
private void ChangeBtnSearchStatus(bool iSsearching)
{
if (!iSsearching)
{
btnSearch.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#4CAF50"));
btnSearch.Content = "开始搜索";
cmbPortNames.IsEnabled = true;
mcmbBaudrate.IsEnabled = true;
txtMinId.IsEnabled = txtMaxId.IsEnabled = true;
txtIdTimeout.IsEnabled = true;
}
else
{
btnSearch.Content = "停止搜索";
btnSearch.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF4C4C"));
cmbPortNames.IsEnabled = false;
mcmbBaudrate.IsEnabled = false;
txtMinId.IsEnabled = txtMaxId.IsEnabled = false;
txtIdTimeout.IsEnabled = false;
}
}
private void _deviceFinder_SearchLog(string message)
{
AppendLog(message);
}
private void AppendLog(string message)
{
//Dispatcher.Invoke(() =>
Dispatcher.BeginInvoke(new Action(()=>
{
var logEntry = new LogEntry { Time = DateTime.Now.ToString("HH:mm:ss.fff"), Message = message };
_logEntries.Add(logEntry);
lvLogs.ItemsSource = null;
lvLogs.ItemsSource = _logEntries;
lvLogs.ScrollIntoView(logEntry);
//File.AppendAllText("search_log.txt", $"{logEntry.Time} - {logEntry.Message}\n");
// 确保 Logs 目录存在
Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath));
File.AppendAllText(LogFilePath, $"{logEntry.Time} - {logEntry.Message}\n");
}));
}
//读取并加载日志
private void LoadConfigLog()
{
Dispatcher.BeginInvoke(new Action(() =>
{
LoadLogs();
}));
}
private void LoadLogs()
{
if (!File.Exists(LogFilePath))
return;
_logEntries.Clear(); // 先清空已有的日志记录
//var lines = File.ReadAllLines("config_log.txt");
var lines = File.ReadAllLines(LogFilePath);
foreach (var line in lines)
{
var parts = line.Split(new[] { " - " }, 2, StringSplitOptions.None);
if (parts.Length == 2)
{
_logEntries.Add(new LogEntry { Time = parts[0], Message = parts[1] });
}
}
// 更新 ListView
lvLogs.ItemsSource = null;
lvLogs.ItemsSource = _logEntries;
// 滚动到最后一条
if (_logEntries.Count > 0)
{
lvLogs.ScrollIntoView(_logEntries[_logEntries.Count - 1]);
}
}
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
if (e.Text.All(char.IsDigit))
{
e.Handled = false; // 如果是数字,允许输入
}
else
{
// 如果当前输入的字符不是数字,并且是中文输入法的拼音或候选字,禁止输入
e.Handled = true;
}
}
private void MenuItem_CopyMessage_Click(object sender, RoutedEventArgs e)
{
if (lvLogs.SelectedItem is LogEntry logEntry)
{
if (!LicenseMana.mIsLicensed)
{
MessageBox.Show(Application.Current.MainWindow, "软件未注册,不能使用此功能。", "提示",
MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
Clipboard.SetText(logEntry.Message);
}
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
if (_isSearching)
{
StopSearch();
}
}
//------------------------------------------------------------------
}
//----------------------------------------------------
}