FeederSequence.xaml.cs 24 KB

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