FeederSequence.xaml.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. using Prism.Commands;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Collections.ObjectModel;
  5. using System.ComponentModel;
  6. using System.Linq;
  7. using System.Runtime.CompilerServices;
  8. using System.Security.Cryptography;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using System.Windows;
  12. using System.Windows.Controls;
  13. using System.Windows.Data;
  14. using System.Windows.Documents;
  15. using System.Windows.Input;
  16. using System.Windows.Media;
  17. using System.Windows.Media.Imaging;
  18. using System.Windows.Navigation;
  19. using System.Windows.Shapes;
  20. using Team.FFFeederService.Enums;
  21. using Team.FFFeederService.Interfaces;
  22. using Team.FFFeederService.Models;
  23. using TeamAAS_VP;
  24. using TeamAAS_VP.Resources.Languages;
  25. using TouchSocket.Core;
  26. namespace TeamAAS_VP.Controls
  27. {
  28. /// <summary>
  29. /// FeederSequence.xaml 的交互逻辑
  30. /// </summary>
  31. public partial class FeederSequence : UserControl, INotifyPropertyChanged
  32. {
  33. private bool _manualStop = false;
  34. public FeederSequence()
  35. {
  36. InitializeComponent();
  37. this.DataContext = this;
  38. SequenceCollection.Clear();
  39. for (int i = 1; i <= 26; i++)
  40. {
  41. SequenceCollection.Add(i);
  42. char chn = (char)('A' + i);
  43. }
  44. }
  45. #region 属性
  46. public IVoiceCoilMotorFeeder Feeder { get; set; }
  47. private ObservableCollection<int> _SequenceCollection = new ObservableCollection<int>();
  48. /// <summary>
  49. /// 序列集
  50. /// </summary>
  51. public ObservableCollection<int> SequenceCollection
  52. {
  53. get { return _SequenceCollection; }
  54. set { SetProperty(ref _SequenceCollection, value); }
  55. }
  56. private int _SelectedSequence = -1;
  57. /// <summary>
  58. /// 当前选中的序列
  59. /// </summary>
  60. public int SelectedSequence
  61. {
  62. get { return _SelectedSequence; }
  63. set { SetProperty(ref _SelectedSequence, value); }
  64. }
  65. private int _CurrentSequencePartCntMax;
  66. /// <summary>
  67. /// 极限值
  68. /// </summary>
  69. public int CurrentSequencePartCntMax
  70. {
  71. get { return _CurrentSequencePartCntMax; }
  72. set { SetProperty(ref _CurrentSequencePartCntMax, value); }
  73. }
  74. private int _CycleRunningTimes;
  75. /// <summary>
  76. /// 循环次数
  77. /// </summary>
  78. public int CycleRunningTimes
  79. {
  80. get { return _CycleRunningTimes; }
  81. set { SetProperty(ref _CycleRunningTimes, value); }
  82. }
  83. private SingleSequenceActionGroup _CurrentSequenceActionGroup;
  84. /// <summary>
  85. /// 序列集
  86. /// </summary>
  87. public SingleSequenceActionGroup CurrentSequenceActionGroup
  88. {
  89. get { return _CurrentSequenceActionGroup; }
  90. set { SetProperty(ref _CurrentSequenceActionGroup, value); }
  91. }
  92. private SingleSequenceAction _SingleSequenceAction1;
  93. /// <summary>
  94. /// 1
  95. /// </summary>
  96. public SingleSequenceAction SingleSequenceAction1
  97. {
  98. get { return _SingleSequenceAction1; }
  99. set { SetProperty(ref _SingleSequenceAction1, value); }
  100. }
  101. private SingleSequenceAction _SingleSequenceAction2;
  102. /// <summary>
  103. /// 2
  104. /// </summary>
  105. public SingleSequenceAction SingleSequenceAction2
  106. {
  107. get { return _SingleSequenceAction2; }
  108. set { SetProperty(ref _SingleSequenceAction2, value); }
  109. }
  110. private SingleSequenceAction _SingleSequenceAction3;
  111. /// <summary>
  112. /// 3
  113. /// </summary>
  114. public SingleSequenceAction SingleSequenceAction3
  115. {
  116. get { return _SingleSequenceAction3; }
  117. set { SetProperty(ref _SingleSequenceAction3, value); }
  118. }
  119. private SingleSequenceAction _SingleSequenceAction4;
  120. /// <summary>
  121. /// 4
  122. /// </summary>
  123. public SingleSequenceAction SingleSequenceAction4
  124. {
  125. get { return _SingleSequenceAction4; }
  126. set { SetProperty(ref _SingleSequenceAction4, value); }
  127. }
  128. private SingleSequenceAction _SingleSequenceAction5;
  129. /// <summary>
  130. /// 5
  131. /// </summary>
  132. public SingleSequenceAction SingleSequenceAction5
  133. {
  134. get { return _SingleSequenceAction5; }
  135. set { SetProperty(ref _SingleSequenceAction5, value); }
  136. }
  137. private SingleSequenceAction _SingleSequenceAction6;
  138. /// <summary>
  139. /// 6
  140. /// </summary>
  141. public SingleSequenceAction SingleSequenceAction6
  142. {
  143. get { return _SingleSequenceAction6; }
  144. set { SetProperty(ref _SingleSequenceAction6, value); }
  145. }
  146. private SingleSequenceAction _SingleSequenceAction7;
  147. /// <summary>
  148. /// 7
  149. /// </summary>
  150. public SingleSequenceAction SingleSequenceAction7
  151. {
  152. get { return _SingleSequenceAction7; }
  153. set { SetProperty(ref _SingleSequenceAction7, value); }
  154. }
  155. #region 属性视图显示
  156. private Visibility _IsVisibility1 = Visibility.Collapsed;
  157. public Visibility IsVisibility1
  158. {
  159. get { return _IsVisibility1; }
  160. set { SetProperty(ref _IsVisibility1, value); }
  161. }
  162. private Visibility _IsVisibility1_2 = Visibility.Collapsed;
  163. public Visibility IsVisibility1_2
  164. {
  165. get { return _IsVisibility1_2; }
  166. set { SetProperty(ref _IsVisibility1_2, value); }
  167. }
  168. private Visibility _IsVisibility2 = Visibility.Collapsed;
  169. public Visibility IsVisibility2
  170. {
  171. get { return _IsVisibility2; }
  172. set { SetProperty(ref _IsVisibility2, value); }
  173. }
  174. private Visibility _IsVisibility2_2 = Visibility.Collapsed;
  175. public Visibility IsVisibility2_2
  176. {
  177. get { return _IsVisibility2_2; }
  178. set { SetProperty(ref _IsVisibility2_2, value); }
  179. }
  180. private Visibility _IsVisibility3 = Visibility.Collapsed;
  181. public Visibility IsVisibility3
  182. {
  183. get { return _IsVisibility3; }
  184. set { SetProperty(ref _IsVisibility3, value); }
  185. }
  186. private Visibility _IsVisibility3_2 = Visibility.Collapsed;
  187. public Visibility IsVisibility3_2
  188. {
  189. get { return _IsVisibility3_2; }
  190. set { SetProperty(ref _IsVisibility3_2, value); }
  191. }
  192. private Visibility _IsVisibility4 = Visibility.Collapsed;
  193. public Visibility IsVisibility4
  194. {
  195. get { return _IsVisibility4; }
  196. set { SetProperty(ref _IsVisibility4, value); }
  197. }
  198. private Visibility _IsVisibility4_2 = Visibility.Collapsed;
  199. public Visibility IsVisibility4_2
  200. {
  201. get { return _IsVisibility4_2; }
  202. set { SetProperty(ref _IsVisibility4_2, value); }
  203. }
  204. private Visibility _IsVisibility5 = Visibility.Collapsed;
  205. public Visibility IsVisibility5
  206. {
  207. get { return _IsVisibility5; }
  208. set { SetProperty(ref _IsVisibility5, value); }
  209. }
  210. private Visibility _IsVisibility5_2 = Visibility.Collapsed;
  211. public Visibility IsVisibility5_2
  212. {
  213. get { return _IsVisibility5_2; }
  214. set { SetProperty(ref _IsVisibility5_2, value); }
  215. }
  216. private Visibility _IsVisibility6 = Visibility.Collapsed;
  217. public Visibility IsVisibility6
  218. {
  219. get { return _IsVisibility6; }
  220. set { SetProperty(ref _IsVisibility6, value); }
  221. }
  222. private Visibility _IsVisibility6_2 = Visibility.Collapsed;
  223. public Visibility IsVisibility6_2
  224. {
  225. get { return _IsVisibility6_2; }
  226. set { SetProperty(ref _IsVisibility6_2, value); }
  227. }
  228. private Visibility _IsVisibility7 = Visibility.Collapsed;
  229. public Visibility IsVisibility7
  230. {
  231. get { return _IsVisibility7; }
  232. set { SetProperty(ref _IsVisibility7, value); }
  233. }
  234. private Visibility _IsVisibility7_2 = Visibility.Collapsed;
  235. public Visibility IsVisibility7_2
  236. {
  237. get { return _IsVisibility7_2; }
  238. set { SetProperty(ref _IsVisibility7_2, value); }
  239. }
  240. #endregion
  241. #endregion
  242. #region 命令
  243. private DelegateCommand _SelectSequenceCommand;
  244. public DelegateCommand SelectSequenceCommand =>
  245. _SelectSequenceCommand ?? (_SelectSequenceCommand = new DelegateCommand(ExecuteSelectSequenceCommand));
  246. private DelegateCommand _StartCommand;
  247. public DelegateCommand StartCommand =>
  248. _StartCommand ?? (_StartCommand = new DelegateCommand(ExecuteStartCommand));
  249. private DelegateCommand _StopCommand;
  250. public DelegateCommand StopCommand =>
  251. _StopCommand ?? (_StopCommand = new DelegateCommand(ExecuteStopCommand));
  252. private DelegateCommand _WriteParamCommand;
  253. public DelegateCommand WriteParamCommand =>
  254. _WriteParamCommand ?? (_WriteParamCommand = new DelegateCommand(ExecuteWriteParamCommand));
  255. private DelegateCommand<int?> _SelectActionCommand1;
  256. public DelegateCommand<int?> SelectActionCommand1 =>
  257. _SelectActionCommand1 ?? (_SelectActionCommand1 = new DelegateCommand<int?>(ExecuteSelectActionCommand1));
  258. private DelegateCommand<int?> _SelectActionCommand2;
  259. public DelegateCommand<int?> SelectActionCommand2 =>
  260. _SelectActionCommand2 ?? (_SelectActionCommand2 = new DelegateCommand<int?>(ExecuteSelectActionCommand2));
  261. private DelegateCommand<int?> _SelectActionCommand3;
  262. public DelegateCommand<int?> SelectActionCommand3 =>
  263. _SelectActionCommand3 ?? (_SelectActionCommand3 = new DelegateCommand<int?>(ExecuteSelectActionCommand3));
  264. private DelegateCommand<int?> _SelectActionCommand4;
  265. public DelegateCommand<int?> SelectActionCommand4 =>
  266. _SelectActionCommand4 ?? (_SelectActionCommand4 = new DelegateCommand<int?>(ExecuteSelectActionCommand4));
  267. private DelegateCommand<int?> _SelectActionCommand5;
  268. public DelegateCommand<int?> SelectActionCommand5 =>
  269. _SelectActionCommand5 ?? (_SelectActionCommand5 = new DelegateCommand<int?>(ExecuteSelectActionCommand5));
  270. private DelegateCommand<int?> _SelectActionCommand6;
  271. public DelegateCommand<int?> SelectActionCommand6 =>
  272. _SelectActionCommand6 ?? (_SelectActionCommand6 = new DelegateCommand<int?>(ExecuteSelectActionCommand6));
  273. private DelegateCommand<int?> _SelectActionCommand7;
  274. public DelegateCommand<int?> SelectActionCommand7 =>
  275. _SelectActionCommand7 ?? (_SelectActionCommand7 = new DelegateCommand<int?>(ExecuteSelectActionCommand7));
  276. #endregion
  277. #region 方法
  278. /// <summary>
  279. /// 选中序列时
  280. /// </summary>
  281. async void ExecuteSelectSequenceCommand()
  282. {
  283. if (SelectedSequence == -1)
  284. {
  285. return;
  286. }
  287. if (Feeder == null || !Feeder.IsConnected)
  288. {
  289. return;
  290. }
  291. try
  292. {
  293. var id = SelectedSequence;
  294. CurrentSequenceActionGroup = await Feeder.GetSequenceGroupAsync(id);
  295. CurrentSequencePartCntMax = CurrentSequenceActionGroup.PartCntMax;
  296. SingleSequenceAction1 = CurrentSequenceActionGroup.SingleSequenceActions[0];
  297. SingleSequenceAction2 = CurrentSequenceActionGroup.SingleSequenceActions[1];
  298. SingleSequenceAction3 = CurrentSequenceActionGroup.SingleSequenceActions[2];
  299. SingleSequenceAction4 = CurrentSequenceActionGroup.SingleSequenceActions[3];
  300. SingleSequenceAction5 = CurrentSequenceActionGroup.SingleSequenceActions[4];
  301. SingleSequenceAction6 = CurrentSequenceActionGroup.SingleSequenceActions[5];
  302. SingleSequenceAction7 = CurrentSequenceActionGroup.SingleSequenceActions[6];
  303. }
  304. catch (Exception ex)
  305. {
  306. LogHelper.WriteLogError(Lang.选中Feeder序列时出错, ex);
  307. }
  308. }
  309. /// <summary>
  310. /// 开始执行序列
  311. /// </summary>
  312. async void ExecuteStartCommand()
  313. {
  314. if (Feeder == null)
  315. {
  316. return;
  317. }
  318. if (SelectedSequence == -1)
  319. {
  320. return;
  321. }
  322. try
  323. {
  324. var needToExecute = CycleRunningTimes;
  325. while (true)
  326. {
  327. var value = await Feeder.StartOneSequenceAsync(SelectedSequence + 1);
  328. await Task.Delay(value);
  329. needToExecute--;
  330. if (needToExecute != 0 && !_manualStop) continue;
  331. _manualStop = !_manualStop;
  332. break;
  333. }
  334. }
  335. catch (Exception ex)
  336. {
  337. LogHelper.WriteLogError(Lang.执行Feeder序列时出错, ex);
  338. }
  339. }
  340. /// <summary>
  341. /// 停止执行序列
  342. /// </summary>
  343. async void ExecuteStopCommand()
  344. {
  345. try
  346. {
  347. if (Feeder == null)
  348. {
  349. return;
  350. }
  351. await Feeder.StopOneSequenceAsync();
  352. _manualStop = true;
  353. }
  354. catch (Exception ex)
  355. {
  356. LogHelper.WriteLogError(Lang.停止Feeder序列时出错, ex);
  357. }
  358. }
  359. /// <summary>
  360. /// 下载
  361. /// </summary>
  362. async void ExecuteWriteParamCommand()
  363. {
  364. try
  365. {
  366. var singleSequenceActions = new[]
  367. {
  368. SingleSequenceAction1,SingleSequenceAction2,SingleSequenceAction3,
  369. SingleSequenceAction4,SingleSequenceAction5,SingleSequenceAction6,
  370. SingleSequenceAction7
  371. };
  372. for (var i = 0; i < singleSequenceActions.Length; i++)
  373. {
  374. await Feeder.SetSequenceAsync(SelectedSequence, i, singleSequenceActions[i]);
  375. }
  376. await Feeder.SaveSequenceAsync();
  377. }
  378. catch (Exception ex)
  379. {
  380. LogHelper.WriteLogError(Lang.保存Feeder序列时出错, ex);
  381. }
  382. }
  383. /// <summary>
  384. /// 选择动作1时触发
  385. /// </summary>
  386. void ExecuteSelectActionCommand1(int? index)
  387. {
  388. switch (index)
  389. {
  390. case null:
  391. return;
  392. case 1:
  393. IsVisibility1 = Visibility.Visible;
  394. IsVisibility1_2 = Visibility.Visible;
  395. break;
  396. case 2:
  397. IsVisibility1 = Visibility.Visible;
  398. IsVisibility1_2 = Visibility.Visible;
  399. break;
  400. case 3:
  401. IsVisibility1 = Visibility.Collapsed;
  402. IsVisibility1_2 = Visibility.Visible;
  403. break;
  404. default:
  405. IsVisibility1 = Visibility.Collapsed;
  406. IsVisibility1_2 = Visibility.Collapsed;
  407. break;
  408. }
  409. }
  410. /// <summary>
  411. /// 选择动作2时触发
  412. /// </summary>
  413. void ExecuteSelectActionCommand2(int? index)
  414. {
  415. switch (index)
  416. {
  417. case null:
  418. return;
  419. case 1:
  420. IsVisibility2 = Visibility.Visible;
  421. IsVisibility2_2 = Visibility.Visible;
  422. break;
  423. case 2:
  424. IsVisibility2 = Visibility.Visible;
  425. IsVisibility2_2 = Visibility.Visible;
  426. break;
  427. case 3:
  428. IsVisibility2 = Visibility.Collapsed;
  429. IsVisibility2_2 = Visibility.Visible;
  430. break;
  431. default:
  432. IsVisibility2 = Visibility.Collapsed;
  433. IsVisibility2_2 = Visibility.Collapsed;
  434. break;
  435. }
  436. }
  437. /// <summary>
  438. /// 选择动作3时触发
  439. /// </summary>
  440. void ExecuteSelectActionCommand3(int? index)
  441. {
  442. switch (index)
  443. {
  444. case null:
  445. return;
  446. case 1:
  447. IsVisibility3 = Visibility.Visible;
  448. IsVisibility3_2 = Visibility.Visible;
  449. break;
  450. case 2:
  451. IsVisibility3 = Visibility.Visible;
  452. IsVisibility3_2 = Visibility.Visible;
  453. break;
  454. case 3:
  455. IsVisibility3 = Visibility.Collapsed;
  456. IsVisibility3_2 = Visibility.Visible;
  457. break;
  458. default:
  459. IsVisibility3 = Visibility.Collapsed;
  460. IsVisibility3_2 = Visibility.Collapsed;
  461. break;
  462. }
  463. }
  464. /// <summary>
  465. /// 选择动作4时触发
  466. /// </summary>
  467. void ExecuteSelectActionCommand4(int? index)
  468. {
  469. switch (index)
  470. {
  471. case null:
  472. return;
  473. case 1:
  474. IsVisibility4 = Visibility.Visible;
  475. IsVisibility4_2 = Visibility.Visible;
  476. break;
  477. case 2:
  478. IsVisibility4 = Visibility.Visible;
  479. IsVisibility4_2 = Visibility.Visible;
  480. break;
  481. case 3:
  482. IsVisibility4 = Visibility.Collapsed;
  483. IsVisibility4_2 = Visibility.Visible;
  484. break;
  485. default:
  486. IsVisibility4 = Visibility.Collapsed;
  487. IsVisibility4_2 = Visibility.Collapsed;
  488. break;
  489. }
  490. }
  491. /// <summary>
  492. /// 选择动作5时触发
  493. /// </summary>
  494. void ExecuteSelectActionCommand5(int? index)
  495. {
  496. switch (index)
  497. {
  498. case null:
  499. return;
  500. case 1:
  501. IsVisibility5 = Visibility.Visible;
  502. IsVisibility5_2 = Visibility.Visible;
  503. break;
  504. case 2:
  505. IsVisibility5 = Visibility.Visible;
  506. IsVisibility5_2 = Visibility.Visible;
  507. break;
  508. case 3:
  509. IsVisibility5 = Visibility.Collapsed;
  510. IsVisibility5_2 = Visibility.Visible;
  511. break;
  512. default:
  513. IsVisibility5 = Visibility.Collapsed;
  514. IsVisibility5_2 = Visibility.Collapsed;
  515. break;
  516. }
  517. }
  518. /// <summary>
  519. /// 选择动作6时触发
  520. /// </summary>
  521. void ExecuteSelectActionCommand6(int? index)
  522. {
  523. switch (index)
  524. {
  525. case null:
  526. return;
  527. case 1:
  528. IsVisibility6 = Visibility.Visible;
  529. IsVisibility6_2 = Visibility.Visible;
  530. break;
  531. case 2:
  532. IsVisibility6 = Visibility.Visible;
  533. IsVisibility6_2 = Visibility.Visible;
  534. break;
  535. case 3:
  536. IsVisibility6 = Visibility.Collapsed;
  537. IsVisibility6_2 = Visibility.Visible;
  538. break;
  539. default:
  540. IsVisibility6 = Visibility.Collapsed;
  541. IsVisibility6_2 = Visibility.Collapsed;
  542. break;
  543. }
  544. }
  545. /// <summary>
  546. /// 选择动作7时触发
  547. /// </summary>
  548. void ExecuteSelectActionCommand7(int? index)
  549. {
  550. switch (index)
  551. {
  552. case null:
  553. return;
  554. case 1:
  555. IsVisibility7 = Visibility.Visible;
  556. IsVisibility7_2 = Visibility.Visible;
  557. break;
  558. case 2:
  559. IsVisibility7 = Visibility.Visible;
  560. IsVisibility7_2 = Visibility.Visible;
  561. break;
  562. case 3:
  563. IsVisibility7 = Visibility.Collapsed;
  564. IsVisibility7_2 = Visibility.Visible;
  565. break;
  566. default:
  567. IsVisibility7 = Visibility.Collapsed;
  568. IsVisibility7_2 = Visibility.Collapsed;
  569. break;
  570. }
  571. }
  572. #endregion
  573. #region 属性更改通知
  574. /// <summary>
  575. /// Occurs when a property value changes.
  576. /// </summary>
  577. public event PropertyChangedEventHandler PropertyChanged;
  578. /// <summary>
  579. /// Checks if a property already matches a desired value. Sets the property and
  580. /// notifies listeners only when necessary.
  581. /// </summary>
  582. /// <typeparam name="T">Type of the property.</typeparam>
  583. /// <param name="storage">Reference to a property with both getter and setter.</param>
  584. /// <param name="value">Desired value for the property.</param>
  585. /// <param name="propertyName">Name of the property used to notify listeners. This
  586. /// value is optional and can be provided automatically when invoked from compilers that
  587. /// support CallerMemberName.</param>
  588. /// <returns>True if the value was changed, false if the existing value matched the
  589. /// desired value.</returns>
  590. protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
  591. {
  592. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  593. storage = value;
  594. RaisePropertyChanged(propertyName);
  595. return true;
  596. }
  597. /// <summary>
  598. /// Checks if a property already matches a desired value. Sets the property and
  599. /// notifies listeners only when necessary.
  600. /// </summary>
  601. /// <typeparam name="T">Type of the property.</typeparam>
  602. /// <param name="storage">Reference to a property with both getter and setter.</param>
  603. /// <param name="value">Desired value for the property.</param>
  604. /// <param name="propertyName">Name of the property used to notify listeners. This
  605. /// value is optional and can be provided automatically when invoked from compilers that
  606. /// support CallerMemberName.</param>
  607. /// <param name="onChanged">Action that is called after the property value has been changed.</param>
  608. /// <returns>True if the value was changed, false if the existing value matched the
  609. /// desired value.</returns>
  610. protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
  611. {
  612. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  613. storage = value;
  614. onChanged?.Invoke();
  615. RaisePropertyChanged(propertyName);
  616. return true;
  617. }
  618. /// <summary>
  619. /// Raises this object's PropertyChanged event.
  620. /// </summary>
  621. /// <param name="propertyName">Name of the property used to notify listeners. This
  622. /// value is optional and can be provided automatically when invoked from compilers
  623. /// that support <see cref="CallerMemberNameAttribute"/>.</param>
  624. protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
  625. {
  626. OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
  627. }
  628. /// <summary>
  629. /// Raises this object's PropertyChanged event.
  630. /// </summary>
  631. /// <param name="args">The PropertyChangedEventArgs</param>
  632. protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
  633. {
  634. PropertyChanged?.Invoke(this, args);
  635. }
  636. #endregion
  637. }
  638. }