using MeterVision.Config; using MeterVision.db; using MeterVision.Dlg; using MeterVision.FreeAi; using MeterVision.model; using MeterVision.Util; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Threading.Tasks; //using System.Linq; //using System.Text; //using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; //using System.Windows.Data; //using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; //using System.Windows.Media; //using System.Windows.Media.Imaging; //using System.Windows.Navigation; //using System.Windows.Shapes; namespace MeterVision.Single { /// /// UCSingleGrid.xaml 的交互逻辑 /// public partial class UCSingleGrid : UserControl, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } //定义数据源 public ObservableCollection SingleDetailItemList { get; set; } //定义事件,用于通知外部组件选中项已更改(用于其它窗体或用户控件注册) public event EventHandler OnSelectedSingDetailItemChanged; private SingleDetailItem _selectedSingleDetailItem; public SingleDetailItem SelectedSingleDetailItem { get => _selectedSingleDetailItem; set { if(_selectedSingleDetailItem != value) { _selectedSingleDetailItem = value; OnPropertyChanged(nameof(SelectedSingleDetailItem)); OnSelectedSingDetailItemChanged?.Invoke(this, new SingleDetailItemChangedEventArgs(value)); } } } public ConfigItem mConfigItem { get; set; } public PageModel SingleDetailPage { get; set; } private int _totalRecord; public int TotalRecords { get => _totalRecord; set { if (_totalRecord != value) { _totalRecord = value; OnPropertyChanged(nameof(TotalRecords)); } } } public UCSingleGrid() { InitializeComponent(); SingleDetailItemList = new ObservableCollection(); dgSingle.ItemsSource = SingleDetailItemList; mConfigItem = ConfigItem.GetConfigItem(); SingleDetailPage = new PageModel { PageSize = mConfigItem.SinglePageSize, PageNumber = 1 }; mConfigItem.OnSinglePageSizeChanged += MConfigItem_OnSinglePageSizeChanged; InitializeAsync(); //CreateDemoData(); this.DataContext = this; } private async void InitializeAsync() { await LoadSingleDetailItemList(); } private async void MConfigItem_OnSinglePageSizeChanged(object sender, PageSizeChangedEventArgs e) { SingleDetailPage.InitDefaulValue(e.PageSize); await LoadSingleDetailItemList(); } public async void RefreshData() { SingleDetailPage.InitDefaulValue(); await LoadSingleDetailItemList(); } public async Task LoadSingleDetailItemList() { SingleDetailItemList.Clear(); try { var result = await Task.Run(() => { return DBSingle.GetPagedSingleDetails(SingleDetailPage.PageNumber, SingleDetailPage.PageSize); }); TotalRecords = result.Item1; SingleDetailPage.PageCount = result.Item2; List singleDetails = result.Item3; //更新数据需要在主线中进行 Application.Current.Dispatcher.Invoke(() => { int index = 0; foreach (TSingleDetail singleDetail in singleDetails) { index++; SingleDetailItem item = new SingleDetailItem(singleDetail); item.Index = index + ((SingleDetailPage.PageNumber - 1) * SingleDetailPage.PageSize); SingleDetailItemList.Add(item); }//foreach SelectedSingleDetailItem = null; }); return true; } catch (Exception ex) { MessageBox.Show(Application.Current.MainWindow, $"加载数据时发生错误:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); return false; } } private void SrcImage_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var image = sender as Image; if (image == null) return; var dataContext = image.DataContext as SingleDetailItem; if (dataContext == null) return; //var dialog = new ImageViewerWindow(dataContext.SourceImagePath) if (!File.Exists(dataContext.SrcImage)) return; var dialog = new imgWindow(dataContext.SrcImage) { Owner = Application.Current.MainWindow }; if(dialog.ShowDialog() == true) { } } private void DstImage_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var image = sender as Image; if (image == null) return; var dataContext = image.DataContext as SingleDetailItem; if (dataContext == null) return; //var dialog = new ImageViewerWindow(dataContext.SourceImagePath) if (!File.Exists(dataContext.DstImage)) return; var dialog = new imgWindow(dataContext.DstImage) { Owner = Application.Current.MainWindow }; if (dialog.ShowDialog() == true) { } } private void UserControl_DragEnter(object sender, DragEventArgs e) { } private void UserControl_PreviewDragOver(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { // 获取拖拽的文件数组 string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); // 检查是否只拖拽了一个文件,并且该文件不是文件夹 if (files.Length == 1 && File.Exists(files[0])) { e.Effects = DragDropEffects.Copy; } else { e.Effects = DragDropEffects.None; } } else { e.Effects = DragDropEffects.None; } e.Handled = true; } private void UserControl_Drop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { // 获取拖拽的文件数组 string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); // 确保只拖拽了一个文件 if (files.Length != 1) { //MessageBox.Show("只能拖拽一个文件。", "错误", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(Application.Current.MainWindow, "只能拖拽一个文件。", "错误", MessageBoxButton.OK, MessageBoxImage.Error); return; } // 获取单个文件路径 string file = files[0]; // 验证文件是否为 JPG 文件 //if (IsJpgFile(file)) // 验证文件是否为有效的 JPG 文件,并且文件大小不超过 100KB if ( (ThisApp.IsJpgFile(file) || ThisApp.IsBmpFile(file) ) && ThisApp.IsFileSizeValid(file) && ThisApp.IsImageDimensionsValid(file)) { // 调用图像处理方法 //ProcessDragFile(file); DragRecong(file); } else { MessageBox.Show(Application.Current.MainWindow, $"文件 {file} 不符合要求:必须是小于 200KB 的 JPG 文件,且图像尺寸必须为 320x240。", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } } public async void DragRecong(string srcImagePath) { var singleDetail = new SingleDetailItem() { SingleDetailId = Guid.NewGuid().ToString(), CreateTime = ThisApp.GetNowTime_yyyyMMddHHmmss(), SrcImage = srcImagePath }; //DBSingle.InsertTSingleDetail0(singleDetail); bool blRun = await RunAI(true,singleDetail); Console.Write($"Run:{blRun}"); if (blRun) { SingleDetailPage.PageNumber = 1; await LoadSingleDetailItemList(); if (SingleDetailItemList.Count > 0) { SelectedSingleDetailItem = SingleDetailItemList[0]; dgSingle.ScrollIntoView(dgSingle.Items[0]); } MessageBox.Show(Application.Current.MainWindow, "识别成功!", "提示", MessageBoxButton.OK, MessageBoxImage.Information); } else { MessageBox.Show(Application.Current.MainWindow, "识别识别!", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } //处理拖拽的文件 //private void ProcessDragFile(string filePath) //{ // //AddNewSingTask(filePath); // InsertFilesWithProgress(new List() { filePath }); //} //public async void InsertFilesWithProgress(List filePaths) //{ // // 弹出一个非模式对话框来显示进度 // ProgressDialog progressDialog = new ProgressDialog() // { // Owner = Application.Current.MainWindow // }; // progressDialog.Show(); // // 任务来异步执行文件插入 // await Task.Run(() => InsertFilesToDatabase(filePaths, progressDialog)); // // 关闭进度对话框 // progressDialog.Close(); // //刷新CurItem // //OnStandItemCountChanged?.Invoke(this, new StandItemCountChangedEventArgs(CurStandItem)); // //刷新数据(并定位第一条) // SingleDetailPage.PageNumber = 1; // LoadSingleDetailItemList(); // SelectedSingleDetailItem = SingleDetailItemList[0]; //} public void InsertFilesToDatabase(List filePaths, ProgressDialog progressDialog) { int totalFiles = filePaths.Count; int currentFile = 0; foreach (var filePath in filePaths) { // 插入文件路径到数据库 //InsertFileToDatabase(filePath); TSingleDetail singleDetail = new TSingleDetail() { SingleDetailId = Guid.NewGuid().ToString(), CreateTime = ThisApp.GetNowTime_yyyyMMddHHmmss(), SrcImage = filePath }; DBSingle.InsertTSingleDetail0(singleDetail); // 更新进度条 currentFile++; UpdateProgress(progressDialog, currentFile, totalFiles); } } public void UpdateProgress(ProgressDialog progressDialog, int currentFile, int totalFiles) { // 更新进度条的进度 double progress = (double)currentFile / totalFiles * 100; progressDialog.UpdateProgress(progress); } public async void NextPage() { if (SingleDetailPage.PageNumber < SingleDetailPage.PageCount) { SingleDetailPage.PageNumber += 1; await LoadSingleDetailItemList(); } } public async void PrePage() { if (SingleDetailPage.PageNumber > 1) { SingleDetailPage.PageNumber -= 1; await LoadSingleDetailItemList(); } } public async void FirstPage() { if (SingleDetailPage.PageNumber > 1) { SingleDetailPage.PageNumber = 1; await LoadSingleDetailItemList(); } } public async void LastPage() { if (SingleDetailPage.PageNumber < SingleDetailPage.PageCount) { SingleDetailPage.PageNumber = SingleDetailPage.PageCount; await LoadSingleDetailItemList(); } } public async void SpeciPage(int pageNumber) { if (pageNumber != SingleDetailPage.PageNumber && pageNumber > 0 && pageNumber <= SingleDetailPage.PageCount) { SingleDetailPage.PageNumber = pageNumber; await LoadSingleDetailItemList(); } } // 辅助方法:查找指定类型的祖先元素 public static T FindAncestor(DependencyObject dependencyObject) where T : DependencyObject { var parent = VisualTreeHelper.GetParent(dependencyObject); if (parent == null) return null; var parentT = parent as T; return parentT ?? FindAncestor(parent); } private void BtnDelDetailItem_Click(object sender, RoutedEventArgs e) { //删除选中项 Button button = sender as Button; if (button == null) return; DataGridRow row = FindAncestor(button); if (row == null) return; //获取当前行绑定的数据项 SingleDetailItem selectedItem = row.Item as SingleDetailItem; DeleteSelectedItem(selectedItem); } private void BtnRecongDetailItem_Click(object sender, RoutedEventArgs e) { Button button = sender as Button; if (button == null) return; DataGridRow row = FindAncestor(button); if (row == null) return; //获取当前行绑定的数据项 SingleDetailItem selectedItem = row.Item as SingleDetailItem; RecongSingleDetail(false, SelectedSingleDetailItem); } private void BtnLogViewer_Click(object sender, RoutedEventArgs e) { Button button = sender as Button; if (button == null) return; DataGridRow row = FindAncestor(button); if (row == null) return; //获取当前行绑定的数据项 SingleDetailItem selectedItem = row.Item as SingleDetailItem; ShowLogViewer(selectedItem); } private void ShowLogViewer(SingleDetailItem selectedItem) { if (selectedItem.LogPath != null && File.Exists(selectedItem.LogPath)) { LogViewerWindow dialog = new LogViewerWindow(selectedItem.DstImage, selectedItem.LogPath) { Owner = Application.Current.MainWindow, WindowStartupLocation = WindowStartupLocation.CenterOwner }; dialog.ShowDialog(); } } private async void DeleteSelectedItem(SingleDetailItem selectedItem) { if (selectedItem == null) return; MessageBoxResult result = MessageBox.Show("确定要删除此条目吗?", "确认删除", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result != MessageBoxResult.Yes) return; string titleInfo = "正在删除,请稍后..."; WaitWindow waitWindow = new WaitWindow(titleInfo) { Owner = Application.Current.MainWindow, WindowStartupLocation = WindowStartupLocation.CenterOwner }; waitWindow.Show(); try { bool deleteSuccess = false; await Task.Run(() => { deleteSuccess = DBSingle.DeleteTSingleDetailById(selectedItem.SingleDetailId); }); if (deleteSuccess) { Application.Current.Dispatcher.Invoke(() => { // 从数据源中移除该条目 SingleDetailItemList.Remove(selectedItem); SelectedSingleDetailItem = null; }); } } catch (Exception ex) { MessageBox.Show(Application.Current.MainWindow, $"删除失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } finally { waitWindow.Close(); } } //清空所有的列表数据 public async void ClearAllSingleDetail() { //清空提示 MessageBoxResult result = MessageBox.Show("确定要清空所有数据吗?", "确认清空", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result != MessageBoxResult.Yes) return; string titleInfo = "正在清空数据,请稍后..."; WaitWindow waitWindow = new WaitWindow(titleInfo) { Owner = Application.Current.MainWindow, WindowStartupLocation = WindowStartupLocation.CenterOwner }; waitWindow.Show(); try { bool blClearAll = false; await Task.Run(() => { blClearAll = DBSingle.ClearTSingleDetailTable(); }); if (blClearAll) { SingleDetailPage.InitDefaulValue(); await LoadSingleDetailItemList(); } } catch (Exception ex) { MessageBox.Show(Application.Current.MainWindow, $"清空失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } finally { waitWindow.Close(); } } private void MiDelete_Click(object sender, RoutedEventArgs e) { if (SelectedSingleDetailItem == null) return; //获取当前行绑定的数据项 DeleteSelectedItem(SelectedSingleDetailItem); } private void MiRecong_Click(object sender, RoutedEventArgs e) { if (SelectedSingleDetailItem == null) return; RecongSingleDetail(false, SelectedSingleDetailItem); } private async void RecongSingleDetail(bool isAdd, SingleDetailItem singleDetailIte) { string jpgFile = singleDetailIte.SrcImage; if (!File.Exists(jpgFile)) { MessageBox.Show(Application.Current.MainWindow, $"文件:{jpgFile}不存在!", "警告", MessageBoxButton.OK, MessageBoxImage.Warning); return; } bool blRun = await RunAI(isAdd, singleDetailIte); if (blRun) { MessageBox.Show(Application.Current.MainWindow, "识别成功!", "提示", MessageBoxButton.OK, MessageBoxImage.Information); } else { MessageBox.Show(Application.Current.MainWindow, "识别失败!", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } private async Task RunAI(bool isAdd,SingleDetailItem singleDetailItem) { FaRun faRun = new FaRun(); faRun.OnAiRealLogInfo += FaRun_OnAiRealLogInfo; string titleInfo = "正在识别,请稍后..."; WaitWindow waitWindow = new WaitWindow(titleInfo) { Owner = Application.Current.MainWindow, WindowStartupLocation = WindowStartupLocation.CenterOwner }; waitWindow.Show(); try { TSingleDetail newSingleDetail = null; bool blRun = await Task.Run(() => { try { ResultModel resultModel = faRun.StartRecognition(singleDetailItem.SrcImage); if (resultModel == null) return false; newSingleDetail = new TSingleDetail(singleDetailItem, resultModel); //更新数据 bool blOpration; if (isAdd) { blOpration = DBSingle.InsertSingleDetail(newSingleDetail); } else { blOpration = DBSingle.UpdateSingleDetail(newSingleDetail); } return blOpration; } catch(Exception ex) { Console.WriteLine(ex.Message); return false; } }); //在主线程中更新DataGrid的Row数据 if (blRun && !isAdd && newSingleDetail != null) { //singleDetailItem = newSingleDetail; ObjectHelper.CopyMatchingFields(newSingleDetail, singleDetailItem); } return blRun; } catch (Exception ex) { MessageBox.Show(Application.Current.MainWindow, $"识别[{singleDetailItem.SrcImage}]时出错:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); return false; } finally { waitWindow.Close(); } } private void FaRun_OnAiRealLogInfo(object sender, AiRealLogEventArgs e) { Console.Write(e.mLogInfo); } private void MiViewLog_Click(object sender, RoutedEventArgs e) { if(SelectedSingleDetailItem != null) { ShowLogViewer(SelectedSingleDetailItem); } } /////////////////////////////////////////////////////////////////////////// } //自定义事件参数类 public class SingleDetailItemChangedEventArgs : EventArgs { public SingleDetailItem SelectedSingleDetailItem { get; } public SingleDetailItemChangedEventArgs(SingleDetailItem selectedData) { SelectedSingleDetailItem = selectedData; } } }