UCStandMain.xaml.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. using MeterVision.Config;
  2. using MeterVision.db;
  3. using MeterVision.Dlg;
  4. using MeterVision.model;
  5. using MeterVision.Util;
  6. using OfficeOpenXml;
  7. using OfficeOpenXml.Style;
  8. using Ookii.Dialogs.Wpf;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Collections.ObjectModel;
  12. using System.ComponentModel;
  13. using System.IO;
  14. using System.Linq;
  15. using System.Text;
  16. using System.Text.RegularExpressions;
  17. using System.Threading.Tasks;
  18. using System.Windows;
  19. using System.Windows.Controls;
  20. using System.Windows.Data;
  21. using System.Windows.Documents;
  22. using System.Windows.Input;
  23. using System.Windows.Media;
  24. using System.Windows.Media.Imaging;
  25. using System.Windows.Navigation;
  26. //using System.Windows.Shapes;
  27. namespace MeterVision.Stand
  28. {
  29. /// <summary>
  30. /// UCStand.xaml 的交互逻辑
  31. /// </summary>
  32. public partial class UCStandMain : UserControl, INotifyPropertyChanged
  33. {
  34. private const int COLUMN_LEFT_WIDTH = 220;
  35. private const int COLUMN_RIGHT_WIDTH = 400;
  36. private bool LeftVisiable = true; //表示左侧的显示状态
  37. private bool RightVisiable = true; //表示右侧的显示状态
  38. public event PropertyChangedEventHandler PropertyChanged;
  39. protected void OnPropertyChanged(string propertyName)
  40. {
  41. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  42. }
  43. public PageModel StandPage { get; set; }
  44. //定义模板目录数据源
  45. public ObservableCollection<StandItem> StandItemList { get; set; }
  46. // 定义"标准答案编辑"依赖属性
  47. public static readonly DependencyProperty IsResultEditingProperty =
  48. DependencyProperty.Register("IsResultEditing", typeof(bool), typeof(UCStandMain), new PropertyMetadata(false));
  49. public bool IsResultEditing
  50. {
  51. get { return (bool)GetValue(IsResultEditingProperty); }
  52. set { SetValue(IsResultEditingProperty, value); }
  53. }
  54. private StandItem _selectedStandItem;
  55. public StandItem SelectedStandItem
  56. {
  57. get => _selectedStandItem;
  58. set
  59. {
  60. _selectedStandItem = value;
  61. OnPropertyChanged(nameof(SelectedStandItem)); //通知更新
  62. ucStandGird.CurStandItem = value;
  63. Apply_UCStandDetaisl_Title(value);
  64. }
  65. }
  66. private int _totalStandRecords;
  67. public int TotalStandRecords
  68. {
  69. get => _totalStandRecords;
  70. set
  71. {
  72. if (_totalStandRecords != value)
  73. {
  74. _totalStandRecords = value;
  75. OnPropertyChanged(nameof(TotalStandRecords));
  76. }
  77. }
  78. }
  79. public CfginiItem mConfigItem { get; set; }
  80. private void Apply_UCStandDetaisl_Title(StandItem standItem)
  81. {
  82. if(standItem == null)
  83. {
  84. //pnlDetailsTitle.Visibility = Visibility.Hidden;
  85. pnlDetailsFunc.Visibility = Visibility.Hidden;
  86. txtStandName.Text = "请选择左侧模板";
  87. }
  88. else
  89. {
  90. //pnlDetailsTitle.Visibility = Visibility.Visible;
  91. pnlDetailsFunc.Visibility = Visibility.Visible;
  92. txtStandName.Text = $"{standItem.Index}. {standItem.StandName}[{standItem.StandCount}]";
  93. }
  94. }
  95. private void InitRightControls(StandDetailItem standDetailsItem)
  96. {
  97. pnlImage.Visibility = txtRightItemIndex.Visibility =
  98. standDetailsItem == null ? Visibility.Collapsed : Visibility.Visible;
  99. pnlResult.Visibility = Visibility.Hidden;
  100. }
  101. public UCStandMain()
  102. {
  103. InitializeComponent();
  104. StandItemList = new ObservableCollection<StandItem>();
  105. dgStand.ItemsSource = StandItemList;
  106. //this.btnStandExport.Click += BtnStandExport_Click;
  107. ucStandGird.OnSelectedStandDetailItemChanged += UcStandGird_OnSelectedStandDetailsItemChanged;
  108. IsResultEditing = false;
  109. Apply_UCStandDetaisl_Title(null);
  110. //SelectedStandItem = null;
  111. InitRightControls(null);
  112. mConfigItem = CfginiItem.GetConfigItem();
  113. StandPage = new PageModel
  114. {
  115. //PageSize = mConfigItem.CatalogPageSize,
  116. PageSize = mConfigItem.StandCatalogPageSize,
  117. PageNumber = 1,
  118. };
  119. //LoadStandItemList();
  120. ucStandGird.OnStandItemCountChanged += UcStandGird_OnStandItemCountChanged;
  121. ucStandGird.OnDeleteStandDetailItem += UcStandGird_OnDeleteStandDetailItem;
  122. mConfigItem.OnStandCatalogPageSizeChanged += MConfigItem_OnStandCatalogPageSizeChanged;
  123. this.DataContext = this;
  124. // 启动异步初始化,确保不会阻塞构造函数
  125. LoadStandItemListAsync();
  126. //控制左右2侧栏目的显示
  127. LeftVisiable = true;
  128. ChangeLeftVisiable(LeftVisiable);
  129. RightVisiable = true;
  130. ChangeRightVisiable(RightVisiable);
  131. }
  132. private async void MConfigItem_OnStandCatalogPageSizeChanged(int pageSize)
  133. {
  134. //throw new NotImplementedException();
  135. StandPage.InitDefaulValue(pageSize);
  136. bool blLoad = await LoadStandItemList();
  137. if (blLoad)
  138. {
  139. SelectedStandItem = null;
  140. }
  141. }
  142. private async void LoadStandItemListAsync()
  143. {
  144. await LoadStandItemList();
  145. }
  146. private void UcStandGird_OnStandItemCountChanged(object sender, StandItemCountChangedEventArgs e)
  147. {
  148. //Detail的数量发生变化
  149. RefreshStandItemById(e.mStandItem.StandId);
  150. }
  151. private void UcStandGird_OnDeleteStandDetailItem(string standId)
  152. {
  153. RefreshStandItemById(standId);
  154. }
  155. private async void RefreshStandItemById(string standId)
  156. {
  157. if ( string.IsNullOrWhiteSpace(standId) ) return;
  158. VStand vStand = null;
  159. await Task.Run(() =>
  160. {
  161. vStand = DBStand.GetVStandById(standId);
  162. });
  163. if (vStand != null)
  164. {
  165. //var NewStandItem = new StandItem(vStand);
  166. foreach (var standItem in StandItemList)
  167. {
  168. if (standItem.StandId == vStand.StandId)
  169. {
  170. // ObjectHelper.CopyMatchingFields(NewStandItem, standItem);
  171. ObjectHelper.CopyMatchingFields(vStand, standItem);
  172. break;
  173. }
  174. }//foreach
  175. }//if vpatch!=null
  176. }
  177. private async Task<bool> LoadStandItemList()
  178. {
  179. StandItemList.Clear();
  180. try
  181. {
  182. var result = await Task.Run(() =>
  183. {
  184. return DBStand.GetPagedVStands(StandPage.PageNumber, StandPage.PageSize);
  185. });
  186. TotalStandRecords = result.Item1;
  187. StandPage.PageCount = result.Item2;
  188. List<VStand> stands = result.Item3;
  189. int index = 0;
  190. foreach (VStand vStand in stands)
  191. {
  192. index++;
  193. StandItem standItem = new StandItem(vStand);
  194. standItem.Index = index + (StandPage.PageNumber - 1) * StandPage.PageSize;
  195. StandItemList.Add(standItem);
  196. }
  197. if(StandItemList.Count > 0)
  198. {
  199. //dgStand.ScrollIntoView(StandItemList[0]);
  200. }
  201. return true;
  202. }
  203. catch (Exception ex)
  204. {
  205. MessageBox.Show(Application.Current.MainWindow,
  206. $"加载数据时发生错误:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
  207. return false;
  208. }
  209. }
  210. private void UcStandGird_OnSelectedStandDetailsItemChanged(object sender, StandDetailItemChangedEventArgs e)
  211. {
  212. InitRightControls(e.SelectedDataItem);
  213. txtRightItemIndex.Text = string.Empty;
  214. if (e.SelectedDataItem != null)
  215. {
  216. ucImageSource.ImageSource = e.SelectedDataItem.SrcImage;
  217. ucImageSource.ImageName = "原始图片";
  218. txtRightResult.Text = e.SelectedDataItem.StandValue;
  219. IsResultEditing = false;
  220. if(SelectedStandItem != null)
  221. {
  222. txtRightItemIndex.Text = $"{SelectedStandItem.Index}. - {e.SelectedDataItem.Index}.";
  223. }
  224. }
  225. }
  226. //导出模板
  227. private void BtnStandExport_Click(object sender, RoutedEventArgs e)
  228. {
  229. //查询所有的数据
  230. if (SelectedStandItem == null) return;
  231. List<TStandDetail> standDetails = DBStand.GetAllStandDetails(SelectedStandItem.StandId);
  232. if (standDetails.Count <= 0) return;
  233. string fileName = $"{SelectedStandItem.StandName}_{standDetails.Count}.xlsx";
  234. //创建保存文件对话框
  235. VistaSaveFileDialog saveFileDialog = new VistaSaveFileDialog
  236. {
  237. Filter = "Excel 文件 (*.xlsx)|*.xlsx",
  238. FileName = fileName,
  239. Title = "选择模板保存路径"
  240. };
  241. // 如果用户选择了路径并点击保存
  242. if (saveFileDialog.ShowDialog() == true){
  243. string titleInfo = "正在导出模板数据,请稍后...";
  244. WaitWindow waitWindow = new WaitWindow(titleInfo)
  245. {
  246. Owner = Application.Current.MainWindow,
  247. WindowStartupLocation = WindowStartupLocation.CenterOwner
  248. };
  249. waitWindow.Show();
  250. string filePath = saveFileDialog.FileName;
  251. try{
  252. // 创建Excel包
  253. using (ExcelPackage package = new ExcelPackage()){
  254. var worksheet = package.Workbook.Worksheets.Add("Sheet1");
  255. // 表头
  256. worksheet.Cells[1, 1].Value = "图像";
  257. worksheet.Cells[1, 2].Value = "标准答案";
  258. // 设置表头样式
  259. using (var range = worksheet.Cells[1, 1, 1, 2])
  260. {
  261. //range.Style.Font.Bold = false;
  262. range.Style.Font.Name = "等线";
  263. range.Style.Font.Size = 11;
  264. //range.Style.Fill.PatternType = ExcelFillStyle.Solid;
  265. //range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightBlue);
  266. range.AutoFitColumns();
  267. }
  268. // 填充数据
  269. for (int i = 0; i < standDetails.Count; i++)
  270. {
  271. worksheet.Cells[i + 2, 1].Value = standDetails[i].SrcImage;
  272. worksheet.Cells[i + 2, 2].Value = standDetails[i].StandValue;
  273. // 设置行字体
  274. worksheet.Cells[i + 2, 1, i + 2, 2].Style.Font.Name = "等线";
  275. worksheet.Cells[i + 2, 1, i + 2, 2].Style.Font.Size = 11;
  276. //worksheet.Cells[i + 2, 1, i + 2, 2].Style.Font.Color.SetColor(System.Drawing.Color.Black);
  277. }
  278. // 设置列宽
  279. worksheet.Column(1).Width = 50; // 姓名列
  280. worksheet.Column(2).Width = 20; // 年龄列
  281. // 或者自动调整列宽
  282. //worksheet.Cells.AutoFitColumns();
  283. // 保存到用户选择的路径
  284. FileInfo excelFile = new FileInfo(filePath);
  285. package.SaveAs(excelFile);
  286. MessageBox.Show("Excel导出成功!");
  287. }
  288. }
  289. catch (Exception ex){
  290. MessageBox.Show($"导出失败: {ex.Message}");
  291. }
  292. waitWindow.Close();
  293. }
  294. }
  295. private void BtnStandImport_Click(object sender, RoutedEventArgs e)
  296. {
  297. //throw new NotImplementedException();
  298. }
  299. private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
  300. {
  301. // 只允许数字输入
  302. e.Handled = !Regex.IsMatch(e.Text, @"^\d$");
  303. }
  304. private void TxtRightResult_PreviewTextInput(object sender, TextCompositionEventArgs e)
  305. {
  306. // 只允许数字输入
  307. e.Handled = !Regex.IsMatch(e.Text, @"^\d$");
  308. }
  309. private void BtnEditRightResult_Click(object sender, RoutedEventArgs e)
  310. {
  311. IsResultEditing = true;
  312. }
  313. private void BtnSubmitRightResult_Click(object sender, RoutedEventArgs e)
  314. {
  315. IsResultEditing = false;
  316. }
  317. private void BtnCancelRightResult_Click(object sender, RoutedEventArgs e)
  318. {
  319. IsResultEditing = false;
  320. }
  321. private async void BtnStandNextPage_Click(object sender, RoutedEventArgs e)
  322. {
  323. if(StandPage.PageNumber < StandPage.PageCount)
  324. {
  325. StandPage.PageNumber += 1;
  326. bool blLoad = await LoadStandItemList();
  327. if(blLoad && StandItemList.Count > 0)
  328. {
  329. dgStand.ScrollIntoView(StandItemList[0]);
  330. }
  331. }
  332. }
  333. private async void BtnStandPrePage_Click(object sender, RoutedEventArgs e)
  334. {
  335. if(StandPage.PageNumber > 1)
  336. {
  337. StandPage.PageNumber -= 1;
  338. bool blLoad = await LoadStandItemList();
  339. if(blLoad && StandItemList.Count > 0)
  340. {
  341. dgStand.ScrollIntoView(StandItemList[0]);
  342. }
  343. }
  344. }
  345. private void BtnStandDetailFirstPage_Click(object sender, RoutedEventArgs e)
  346. {
  347. ucStandGird.FirstPage();
  348. }
  349. private void BtnStandDetailNextPage_Click(object sender, RoutedEventArgs e)
  350. {
  351. ucStandGird.NextPage();
  352. }
  353. private void BtnStanddetailPrePage_Click(object sender, RoutedEventArgs e)
  354. {
  355. ucStandGird.PrePage();
  356. }
  357. private void BtnStandDetailLastPage_Click(object sender, RoutedEventArgs e)
  358. {
  359. ucStandGird.LastPage();
  360. }
  361. private void BtnStandDetailSpeciPage_Click(object sender, RoutedEventArgs e)
  362. {
  363. try
  364. {
  365. int pageNumber = int.Parse(txtStandDetailPageNumber.Text.ToString());
  366. ucStandGird.SpeciPage(pageNumber);
  367. }
  368. catch
  369. {
  370. }
  371. }
  372. private async void BtnAddStand_Click(object sender, RoutedEventArgs e)
  373. {
  374. //List<string> tableNames = SQLiteHelper.GetAllTables();
  375. var dialog = new AddStandDialog()
  376. {
  377. Owner = Application.Current.MainWindow,
  378. WindowStartupLocation = WindowStartupLocation.CenterOwner
  379. };
  380. if (dialog.ShowDialog() == true)
  381. {
  382. StandPage.InitDefaulValue();
  383. bool blLoad = await LoadStandItemList();
  384. if (blLoad && StandItemList.Count > 0)
  385. {
  386. SelectedStandItem = StandItemList[0];
  387. dgStand.ScrollIntoView(StandItemList[0]);
  388. }
  389. }
  390. }
  391. private async void BtnDelStand_Click(object sender, RoutedEventArgs e)
  392. {
  393. bool blDelete = await DeleteStandItem();
  394. }
  395. private async Task<bool> DeleteStandItem()
  396. {
  397. bool blDelete = false;
  398. if (SelectedStandItem == null) return blDelete;
  399. MessageBoxResult result = MessageBox.Show(
  400. $"您确定要删除[{SelectedStandItem.StandName}]任务吗?\n此操作无法撤销。",
  401. "确认删除",
  402. MessageBoxButton.YesNo, // 提供“是”和“否”按钮
  403. MessageBoxImage.Warning // 使用警告图标
  404. );
  405. if (result != MessageBoxResult.Yes)
  406. {
  407. return blDelete;
  408. }
  409. //开始删除操作
  410. string titleInfo = "正在删除,请稍候...";
  411. WaitWindow waitWindow = new WaitWindow(titleInfo)
  412. {
  413. Owner = Application.Current.MainWindow,
  414. WindowStartupLocation = WindowStartupLocation.CenterOwner
  415. };
  416. waitWindow.Show();
  417. try
  418. {
  419. //执行异步删除逻辑
  420. bool deleteSuccess = false;
  421. await Task.Run(() =>
  422. {
  423. deleteSuccess = DBStand.DeleteStandAndDetails(SelectedStandItem.StandId);
  424. //Task.Delay(200).Wait(); // 模拟延迟
  425. });
  426. if (deleteSuccess)
  427. {
  428. //await LoadStandItemList();
  429. // 在 UI 线程上更新 ObservableCollection
  430. Application.Current.Dispatcher.Invoke(() =>
  431. {
  432. StandItemList.Remove(SelectedStandItem);
  433. SelectedStandItem = null;
  434. TotalStandRecords -= 1;
  435. });
  436. blDelete = true;
  437. }
  438. }
  439. catch (Exception ex)
  440. {
  441. MessageBox.Show(Application.Current.MainWindow, $"删除失败:{ex.Message}", "错误",
  442. MessageBoxButton.OK, MessageBoxImage.Error);
  443. }
  444. finally
  445. {
  446. //关闭等待窗口
  447. waitWindow.Close();
  448. }
  449. return blDelete;
  450. }
  451. private async void BtnRefresh_Click(object sender, RoutedEventArgs e)
  452. {
  453. StandPage.InitDefaulValue();
  454. bool blLoad = await LoadStandItemList();
  455. if (blLoad && StandItemList.Count > 0)
  456. {
  457. dgStand.ScrollIntoView(StandItemList[0]);
  458. }
  459. }
  460. private async void MiDeleteStand_Click(object sender, RoutedEventArgs e)
  461. {
  462. bool blDelete = await DeleteStandItem();
  463. }
  464. private void MiUpdateStandname_Click(object sender, RoutedEventArgs e)
  465. {
  466. if (SelectedStandItem == null) return;
  467. EditNameDlg editNameDlg = new EditNameDlg("模板", SelectedStandItem.StandName)
  468. {
  469. Owner = Application.Current.MainWindow,
  470. WindowStartupLocation = WindowStartupLocation.CenterOwner
  471. };
  472. if (editNameDlg.ShowDialog() == true)
  473. {
  474. UpdateStandName(SelectedStandItem, editNameDlg.EditName);
  475. }
  476. }
  477. private async void UpdateStandName(StandItem standItem,string newStandName)
  478. {
  479. try
  480. {
  481. bool blUpdate = false;
  482. await Task.Run(() =>
  483. {
  484. blUpdate = DBStand.UpdateStandName(standItem.StandId, newStandName);
  485. });
  486. if (blUpdate)
  487. {
  488. standItem.StandName = newStandName;
  489. }
  490. else
  491. {
  492. MessageBox.Show(Application.Current.MainWindow, $"修改模板名称失败。", "警告",
  493. MessageBoxButton.OK, MessageBoxImage.Warning);
  494. }
  495. }
  496. catch(Exception ex)
  497. {
  498. MessageBox.Show(Application.Current.MainWindow, $"修改模板名称:{ex.Message}错误", "错误",
  499. MessageBoxButton.OK, MessageBoxImage.Error);
  500. }
  501. }
  502. private void BtnRefreshDetail_Click(object sender, RoutedEventArgs e)
  503. {
  504. ucStandGird.CurStandItem = null;
  505. ucStandGird.CurStandItem = SelectedStandItem;
  506. }
  507. private async void BtnSelectImageFloder_Click(object sender, RoutedEventArgs e)
  508. {
  509. // 创建 VistaFolderBrowserDialog 实例
  510. var dialog = new VistaFolderBrowserDialog();
  511. dialog.Description = "请选择模板图片文件夹";
  512. dialog.UseDescriptionForTitle = true; // 使用 Description 作为窗口标题
  513. // 显示对话框并检查用户是否点击了“确定”
  514. if (dialog.ShowDialog() == true)
  515. {
  516. // 获取用户选择的文件夹路径
  517. string selectedFolderPath = dialog.SelectedPath;
  518. await ucStandGird.ImportStandImageFloder(selectedFolderPath);
  519. }
  520. }
  521. private void BtnLeftCtl_Click(object sender, RoutedEventArgs e)
  522. {
  523. bool visiable = !LeftVisiable;
  524. ChangeLeftVisiable(visiable);
  525. }
  526. private void BtnRightCtl_Click(object sender, RoutedEventArgs e)
  527. {
  528. bool visiable = !RightVisiable;
  529. ChangeRightVisiable(visiable);
  530. }
  531. private void ChangeLeftVisiable(bool visiable)
  532. {
  533. LeftVisiable = visiable;
  534. colLeft.Width = new GridLength(visiable ? COLUMN_LEFT_WIDTH : 0);
  535. btnLeftCtl.Content = visiable ? "◀️" : "▶️";
  536. btnLeftCtl.ToolTip = visiable ? "点击隐藏左侧栏" : "点击显示左侧栏";
  537. }
  538. private void ChangeRightVisiable(bool visiable)
  539. {
  540. RightVisiable = visiable;
  541. colRight.Width = new GridLength(visiable ? COLUMN_RIGHT_WIDTH : 0);
  542. btnRightCtl.Content = visiable ? "▶️" : "◀️";
  543. btnRightCtl.ToolTip = visiable ? "点击隐藏右侧栏" : "点击显示右侧栏";
  544. }
  545. /////////////////////////////////////////////////////////////////////////////
  546. }
  547. }