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(); } } //------------------------------------------------------------------ } //---------------------------------------------------- }