PageRenderTime 66ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ManagerWin8/DeviceHive.ManagerWin8/DevicePage.xaml.cs

https://github.com/devicehive/devicehive-.net
C# | 713 lines | 634 code | 61 blank | 18 comment | 82 complexity | b6c4f2a3f9da18332552ae6863850dd1 MD5 | raw file
Possible License(s): MIT
  1. using Callisto.Controls;
  2. using DeviceHive.Client;
  3. using DeviceHive.ManagerWin8.Common;
  4. using Newtonsoft.Json.Linq;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Collections.ObjectModel;
  8. using System.Diagnostics;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using System.Windows.Input;
  14. using Windows.Foundation;
  15. using Windows.Foundation.Collections;
  16. using Windows.UI;
  17. using Windows.UI.Core;
  18. using Windows.UI.Popups;
  19. using Windows.UI.Xaml;
  20. using Windows.UI.Xaml.Controls;
  21. using Windows.UI.Xaml.Controls.Primitives;
  22. using Windows.UI.Xaml.Data;
  23. using Windows.UI.Xaml.Input;
  24. using Windows.UI.Xaml.Media;
  25. using Windows.UI.Xaml.Navigation;
  26. // The Group Detail Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234229
  27. namespace DeviceHive.ManagerWin8
  28. {
  29. /// <summary>
  30. /// A page that displays an overview of a single group, including a preview of the items
  31. /// within the group.
  32. /// </summary>
  33. public sealed partial class DevicePage : DeviceHive.ManagerWin8.Common.LayoutAwarePage
  34. {
  35. Guid deviceId;
  36. Device device;
  37. List<Tab> tabList = new List<Tab>();
  38. Tab currentTab;
  39. bool equipmentInited;
  40. IncrementalLoadingCollection<Notification> notificationsObservable;
  41. IncrementalLoadingCollection<Command> commandsObservable;
  42. CancellationTokenSource notificationsCancellationSource;
  43. CancellationTokenSource commandsCancellationSource;
  44. CancellationTokenSource commandResultCancellatonSource;
  45. DateTime? filterNotificationsStart;
  46. DateTime? filterNotificationsEnd;
  47. DateTime? filterCommandsStart;
  48. DateTime? filterCommandsEnd;
  49. Command commandSelected;
  50. public DevicePage()
  51. {
  52. this.InitializeComponent();
  53. }
  54. /// <summary>
  55. /// Populates the page with content passed during navigation. Any saved state is also
  56. /// provided when recreating a page from a prior session.
  57. /// </summary>
  58. /// <param name="navigationParameter">The parameter value passed to
  59. /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
  60. /// </param>
  61. /// <param name="pageState">A dictionary of state preserved by this page during an earlier
  62. /// session. This will be null the first time a page is visited.</param>
  63. protected override async void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
  64. {
  65. deviceId = (Guid)navigationParameter;
  66. filterNotificationsStart = DateTime.Now.AddDays(-7);
  67. filterCommandsStart = DateTime.Now.AddDays(-7);
  68. await LoadDevice();
  69. if (device == null)
  70. {
  71. return;
  72. }
  73. tabList.Add(new Tab("Summary", "SummaryState", true)
  74. {
  75. Refresh = () =>
  76. {
  77. LoadDevice();
  78. }
  79. });
  80. tabList.Add(new Tab("Notifications", "NotificationsState")
  81. {
  82. Select = () =>
  83. {
  84. if (NotificationsObservable == null)
  85. {
  86. LoadNotifications();
  87. }
  88. else if (NotificationsObservable.WasAnySuccessLoading)
  89. {
  90. StartPollNotifications();
  91. }
  92. },
  93. Deselect = StopPollNotifications,
  94. Refresh = RefreshNotifications,
  95. Filter = (sender) =>
  96. {
  97. ShowFilterFlyout(sender, filterNotificationsStart, filterNotificationsEnd, (s, e) => {
  98. filterNotificationsStart = s;
  99. filterNotificationsEnd = e;
  100. RefreshNotifications();
  101. });
  102. }
  103. });
  104. tabList.Add(new Tab("Commands", "CommandsState")
  105. {
  106. Select = async () =>
  107. {
  108. if (CommandsObservable == null)
  109. {
  110. LoadCommands();
  111. }
  112. else if (CommandsObservable.WasAnySuccessLoading)
  113. {
  114. StartPollCommands();
  115. }
  116. },
  117. Deselect = () =>
  118. {
  119. StopPollCommands();
  120. StopPollCommandResult();
  121. },
  122. Refresh = RefreshCommands,
  123. Filter = (sender) =>
  124. {
  125. ShowFilterFlyout(sender, filterCommandsStart, filterCommandsEnd, (s, e) =>
  126. {
  127. filterCommandsStart = s;
  128. filterCommandsEnd = e;
  129. RefreshCommands();
  130. });
  131. }
  132. });
  133. tabList.Add(new Tab("Equipment", "EquipmentState")
  134. {
  135. Select = () =>
  136. {
  137. if (!equipmentInited)
  138. {
  139. equipmentInited = true;
  140. LoadEquipment();
  141. }
  142. },
  143. Refresh = () =>
  144. {
  145. if (!IsLoading)
  146. {
  147. LoadEquipment();
  148. }
  149. }
  150. });
  151. DefaultViewModel["Tabs"] = tabList;
  152. CommandSelected = null;
  153. }
  154. protected override void SaveState(Dictionary<string, object> pageState)
  155. {
  156. StopPollCommands();
  157. StopPollNotifications();
  158. StopPollCommandResult();
  159. }
  160. void ShowFilterFlyout(object sender, DateTime? start, DateTime? end, Action<DateTime?, DateTime?> filterAction)
  161. {
  162. Flyout flyOut = new Flyout();
  163. flyOut.Width = 300;
  164. flyOut.PlacementTarget = sender as UIElement;
  165. flyOut.Placement = PlacementMode.Top;
  166. flyOut.Background = new SolidColorBrush(Colors.Black);
  167. StackPanel filterPanel = new StackPanel();
  168. filterPanel.Margin = new Thickness(10);
  169. filterPanel.Orientation = Orientation.Vertical;
  170. filterPanel.Children.Add(new TextBlock() { Text = "Start time", FontSize = 14.8 });
  171. TextBox filterStart = new TextBox();
  172. filterPanel.Children.Add(filterStart);
  173. filterPanel.Children.Add(new TextBlock() { Text = "End time", FontSize = 14.8, Margin = new Thickness(0, 10, 0, 0) });
  174. TextBox filterEnd = new TextBox();
  175. filterPanel.Children.Add(filterEnd);
  176. filterPanel.Children.Add(new TextBlock() { Text = "Leave field empty to start polling new data from server" });
  177. Button filterDoButton = new Button() { Content = "Filter", Margin = new Thickness(0, 10, 0, 0) };
  178. filterPanel.Children.Add(filterDoButton);
  179. filterStart.Text = start != null ? start.ToString() : "";
  180. filterEnd.Text = end != null ? end.ToString() : "";
  181. filterDoButton.Command = new DelegateCommand(() =>
  182. {
  183. start = null;
  184. end = null;
  185. DateTime newStart, newEnd;
  186. if (filterStart.Text != "")
  187. {
  188. if (DateTime.TryParse(filterStart.Text, out newStart))
  189. {
  190. start = newStart;
  191. }
  192. else
  193. {
  194. new MessageDialog("Wrong start date", "Filter").ShowAsync();
  195. return;
  196. }
  197. }
  198. if (filterEnd.Text != "")
  199. {
  200. if (DateTime.TryParse(filterEnd.Text, out newEnd))
  201. {
  202. end = newEnd;
  203. }
  204. else
  205. {
  206. new MessageDialog("Wrong end date", "Filter").ShowAsync();
  207. return;
  208. }
  209. }
  210. filterAction(start, end);
  211. });
  212. flyOut.Content = filterPanel;
  213. flyOut.IsOpen = true;
  214. }
  215. public IncrementalLoadingCollection<Notification> NotificationsObservable
  216. {
  217. get { return notificationsObservable; }
  218. set
  219. {
  220. notificationsObservable = value;
  221. DefaultViewModel["Notifications"] = notificationsObservable;
  222. }
  223. }
  224. public IncrementalLoadingCollection<Command> CommandsObservable
  225. {
  226. get { return commandsObservable; }
  227. set
  228. {
  229. commandsObservable = value;
  230. DefaultViewModel["Commands"] = commandsObservable;
  231. }
  232. }
  233. public Command CommandSelected
  234. {
  235. get { return commandSelected; }
  236. set
  237. {
  238. commandSelected = value;
  239. DefaultViewModel["IsCommandSelected"] = commandSelected != null;
  240. BottomAppBar.IsOpen = commandSelected != null;
  241. }
  242. }
  243. void RefreshNotifications()
  244. {
  245. if (!IsLoading)
  246. {
  247. LoadNotifications();
  248. }
  249. }
  250. void RefreshCommands()
  251. {
  252. if (!IsLoading)
  253. {
  254. LoadCommands();
  255. }
  256. }
  257. void StopPollNotifications()
  258. {
  259. if (notificationsCancellationSource != null && !notificationsCancellationSource.IsCancellationRequested)
  260. {
  261. Debug.WriteLine("NTF POLL CANCEL");
  262. notificationsCancellationSource.Cancel();
  263. }
  264. }
  265. void StopPollCommands()
  266. {
  267. if (commandsCancellationSource != null && !commandsCancellationSource.IsCancellationRequested)
  268. {
  269. Debug.WriteLine("CMD POLL CANCEL");
  270. commandsCancellationSource.Cancel();
  271. }
  272. }
  273. async Task LoadDevice()
  274. {
  275. LoadingItems++;
  276. try
  277. {
  278. device = await ClientService.Current.GetDeviceAsync(deviceId);
  279. DefaultViewModel["Device"] = device;
  280. }
  281. catch (Exception ex)
  282. {
  283. new MessageDialog(ex.Message, "Error").ShowAsync();
  284. }
  285. LoadingItems--;
  286. }
  287. void LoadNotifications()
  288. {
  289. StopPollNotifications();
  290. bool loaded = false;
  291. NotificationFilter filter = new NotificationFilter()
  292. {
  293. End = filterNotificationsEnd,
  294. Start = filterNotificationsStart,
  295. SortOrder = SortOrder.DESC
  296. };
  297. var list = new IncrementalLoadingCollection<Notification>(async (take, skip) =>
  298. {
  299. filter.Skip = (int)skip;
  300. filter.Take = (int)take;
  301. try
  302. {
  303. Debug.WriteLine("NTF LOAD START");
  304. var notifications = await ClientService.Current.GetNotificationsAsync(deviceId, filter);
  305. Debug.WriteLine("NTF LOAD END");
  306. return notifications;
  307. }
  308. catch (Exception ex)
  309. {
  310. Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
  311. {
  312. new MessageDialog(ex.Message, "Error").ShowAsync();
  313. });
  314. throw ex;
  315. }
  316. }, 20);
  317. list.IsLoadingChanged += (s, isLoading) =>
  318. {
  319. LoadingItems += isLoading ? 1 : -1;
  320. if (!isLoading && !loaded)
  321. {
  322. StartPollNotifications();
  323. if (s.Count > 0)
  324. {
  325. filter.End = s.First().Timestamp;
  326. }
  327. loaded = true;
  328. }
  329. };
  330. NotificationsObservable = list;
  331. }
  332. async void StartPollNotifications()
  333. {
  334. if (filterNotificationsEnd != null)
  335. {
  336. return;
  337. }
  338. StopPollNotifications();
  339. notificationsCancellationSource = new CancellationTokenSource();
  340. Debug.WriteLine("NTF POLL START");
  341. await ClientService.Current.PollNotifications((notificationsPolled) =>
  342. {
  343. foreach (Notification notification in notificationsPolled)
  344. {
  345. NotificationsObservable.Insert(0, notification);
  346. }
  347. }, deviceId, NotificationsObservable.Any() ? (DateTime?)NotificationsObservable.Max(n => n.Timestamp.Value) : filterNotificationsStart, notificationsCancellationSource.Token);
  348. Debug.WriteLine("NTF POLL END");
  349. }
  350. void LoadCommands()
  351. {
  352. StopPollCommands();
  353. StopPollCommandResult();
  354. bool loaded = false;
  355. CommandFilter filter = new CommandFilter()
  356. {
  357. End = filterCommandsEnd,
  358. Start = filterCommandsStart,
  359. SortOrder = SortOrder.DESC
  360. };
  361. var list = new IncrementalLoadingCollection<Command>(async (take, skip) =>
  362. {
  363. filter.Skip = (int)skip;
  364. filter.Take = (int)take;
  365. try
  366. {
  367. Debug.WriteLine("CMD LOAD START");
  368. var commands = await ClientService.Current.GetCommandsAsync(deviceId, filter);
  369. Debug.WriteLine("CMD LOAD END");
  370. return commands;
  371. }
  372. catch (Exception ex)
  373. {
  374. Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
  375. {
  376. new MessageDialog(ex.Message, "Error").ShowAsync();
  377. });
  378. throw ex;
  379. }
  380. }, 20);
  381. list.IsLoadingChanged += (s, isLoading) =>
  382. {
  383. LoadingItems += isLoading ? 1 : -1;
  384. if (!isLoading && !loaded)
  385. {
  386. StartPollCommands();
  387. if (s.Count > 0)
  388. {
  389. filter.End = s.First().Timestamp;
  390. }
  391. loaded = true;
  392. }
  393. };
  394. CommandsObservable = list;
  395. }
  396. async void StartPollCommands()
  397. {
  398. if (CommandsObservable == null || filterCommandsEnd != null)
  399. {
  400. return;
  401. }
  402. StopPollCommands();
  403. commandsCancellationSource = new CancellationTokenSource();
  404. Debug.WriteLine("CMD POLL START");
  405. await ClientService.Current.PollCommands((commandsPolled) =>
  406. {
  407. foreach (Command command in commandsPolled)
  408. {
  409. CommandsObservable.Insert(0, command);
  410. }
  411. }, deviceId, CommandsObservable.Any() ? (DateTime?)CommandsObservable.Max(n => n.Timestamp.Value) : filterCommandsStart, commandsCancellationSource.Token);
  412. Debug.WriteLine("CMD POLL END");
  413. }
  414. async Task LoadEquipment()
  415. {
  416. LoadingItems++;
  417. try
  418. {
  419. GC.Collect();
  420. Debug.WriteLine("EQP LOAD START");
  421. var equipment = await ClientService.Current.GetEquipmentAsync((int)device.DeviceClass.Id);
  422. Debug.WriteLine("EQP LOAD 50%");
  423. var equipmentState = await ClientService.Current.GetEquipmentStateAsync(deviceId);
  424. Debug.WriteLine("EQP LOAD END");
  425. var equipmentInfo = new List<EquipmentStateInfo>();
  426. foreach (DeviceEquipmentState state in equipmentState)
  427. {
  428. equipmentInfo.Add(new EquipmentStateInfo()
  429. {
  430. Equipment = equipment.Find(eq => eq.Code == state.Id),
  431. State = state
  432. });
  433. }
  434. DefaultViewModel["Equipment"] = equipmentInfo;
  435. }
  436. catch (Exception ex)
  437. {
  438. new MessageDialog(ex.Message, "Error").ShowAsync();
  439. }
  440. LoadingItems--;
  441. }
  442. private void Tabs_Checked(object sender, RoutedEventArgs e)
  443. {
  444. // Mirror the change into the CollectionViewSource used by the corresponding ComboBox
  445. // to ensure that the change is reflected when snapped
  446. if (tabsViewSource.View != null)
  447. {
  448. var filter = (sender as FrameworkElement).DataContext;
  449. tabsViewSource.View.MoveCurrentTo(filter);
  450. }
  451. }
  452. private sealed class EquipmentStateInfo : DeviceEquipmentState
  453. {
  454. public Equipment Equipment { get; set; }
  455. public DeviceEquipmentState State { get; set; }
  456. }
  457. private sealed class Tab : BindableBase
  458. {
  459. private String _name;
  460. private int _count;
  461. private bool _active;
  462. private string _visualStateName;
  463. public Tab(String name, string visualStateName, bool active = false)
  464. {
  465. this.VisualStateName = visualStateName;
  466. this.Name = name;
  467. this.Active = active;
  468. }
  469. public override String ToString()
  470. {
  471. return Description;
  472. }
  473. public string VisualStateName
  474. {
  475. get { return _visualStateName; }
  476. private set { _visualStateName = value; }
  477. }
  478. public String Name
  479. {
  480. get { return _name; }
  481. set { if (this.SetProperty(ref _name, value)) this.OnPropertyChanged("Description"); }
  482. }
  483. public int Count
  484. {
  485. get { return _count; }
  486. set { if (this.SetProperty(ref _count, value)) this.OnPropertyChanged("Description"); }
  487. }
  488. public bool Active
  489. {
  490. get { return _active; }
  491. set { this.SetProperty(ref _active, value); }
  492. }
  493. public Action<object> Filter { get; set; }
  494. public Action Refresh { get; set; }
  495. public Action Select { get; set; }
  496. public Action Deselect { get; set; }
  497. public String Description
  498. {
  499. get
  500. {
  501. if (Count > 0)
  502. {
  503. return String.Format("{0} ({1})", Name, Count);
  504. }
  505. else
  506. {
  507. return Name;
  508. }
  509. }
  510. }
  511. }
  512. private void Tab_SelectionChanged(object sender, SelectionChangedEventArgs e)
  513. {
  514. var deselectedTab = e.RemovedItems.FirstOrDefault() as Tab;
  515. if (deselectedTab != null)
  516. {
  517. deselectedTab.Active = false;
  518. if (deselectedTab.Deselect != null)
  519. {
  520. deselectedTab.Deselect();
  521. }
  522. }
  523. var selectedTab = e.AddedItems.FirstOrDefault() as Tab;
  524. if (selectedTab != null)
  525. {
  526. currentTab = selectedTab;
  527. selectedTab.Active = true;
  528. filterButton.Visibility = selectedTab.Filter != null ? Visibility.Visible : Visibility.Collapsed;
  529. refreshButton.Visibility = selectedTab.Refresh != null ? Visibility.Visible : Visibility.Collapsed;
  530. if (selectedTab.Select != null)
  531. {
  532. selectedTab.Select();
  533. }
  534. VisualStateManager.GoToState(this, selectedTab.VisualStateName, true);
  535. }
  536. }
  537. private void Refresh_Tapped(object sender, TappedRoutedEventArgs e)
  538. {
  539. if (currentTab != null && currentTab.Refresh != null)
  540. {
  541. currentTab.Refresh();
  542. }
  543. }
  544. private void Filter_Tapped(object sender, TappedRoutedEventArgs e)
  545. {
  546. if (currentTab != null && currentTab.Filter != null)
  547. {
  548. currentTab.Filter(sender);
  549. }
  550. }
  551. private void SendCommand_Tapped(object sender, TappedRoutedEventArgs e)
  552. {
  553. Flyout flyOut = new Flyout();
  554. flyOut.Width = 300;
  555. flyOut.PlacementTarget = sender as UIElement;
  556. flyOut.Placement = PlacementMode.Top;
  557. flyOut.Background = new SolidColorBrush(Colors.Black);
  558. StackPanel panel = new StackPanel();
  559. panel.Margin = new Thickness(10);
  560. panel.Orientation = Orientation.Vertical;
  561. panel.Children.Add(new TextBlock() { Text = "Command name", FontSize = 14.8 });
  562. TextBox commandName = new TextBox();
  563. panel.Children.Add(commandName);
  564. panel.Children.Add(new TextBlock() { Text = "Params", FontSize = 14.8, Margin = new Thickness(0, 10, 0, 0) });
  565. TextBox commandParams = new TextBox();
  566. panel.Children.Add(commandParams);
  567. panel.Children.Add(new TextBlock() { Text = "JSON or empty string" });
  568. Button sendButton = new Button() { Content = "Send", Margin = new Thickness(0, 10, 0, 0) };
  569. panel.Children.Add(sendButton);
  570. if (CommandSelected != null)
  571. {
  572. commandName.Text = CommandSelected.Name;
  573. commandParams.Text = (string)new ObjectToJsonStringConverter().Convert(CommandSelected.Parameters, null, null, null);
  574. }
  575. sendButton.Command = new DelegateCommand(async () =>
  576. {
  577. if (commandName.Text.Trim() == "")
  578. {
  579. new MessageDialog("Empty command name", "Send command").ShowAsync();
  580. return;
  581. }
  582. panel.ControlsEnable(false);
  583. LoadingItems++;
  584. try
  585. {
  586. var command = new Command(commandName.Text, JObject.Parse(commandParams.Text));
  587. StopPollCommandResult();
  588. Debug.WriteLine("CMD SEND START");
  589. var commandSent = await ClientService.Current.SendCommandAsync(deviceId, command);
  590. Debug.WriteLine("CMD SEND END");
  591. StartPollCommandResult((int)commandSent.Id);
  592. flyOut.IsOpen = false;
  593. }
  594. catch (Exception ex)
  595. {
  596. new MessageDialog(ex.Message, "Send command").ShowAsync();
  597. }
  598. panel.ControlsEnable(true);
  599. LoadingItems--;
  600. });
  601. flyOut.Content = panel;
  602. flyOut.IsOpen = true;
  603. }
  604. async void StartPollCommandResult(int commandId)
  605. {
  606. StopPollCommandResult();
  607. commandResultCancellatonSource = new CancellationTokenSource();
  608. Debug.WriteLine("CMD SENT POLL START");
  609. var commandResult = await ClientService.Current.WaitCommandAsync(deviceId, commandId, commandResultCancellatonSource.Token);
  610. Debug.WriteLine("CMD SENT POLL END");
  611. if (commandResult != null)
  612. {
  613. if (CommandsObservable == null)
  614. {
  615. return;
  616. }
  617. foreach (Command command in CommandsObservable)
  618. {
  619. if (commandResult.Id == command.Id)
  620. {
  621. // Command class doesn't implement INotifyPropertyChanded,
  622. // so replace old command by command with result
  623. var index = commandsObservable.IndexOf(command);
  624. commandsObservable.RemoveAt(index);
  625. commandsObservable.Insert(index, commandResult);
  626. break;
  627. }
  628. }
  629. }
  630. }
  631. void StopPollCommandResult()
  632. {
  633. if (commandResultCancellatonSource != null && !commandResultCancellatonSource.IsCancellationRequested)
  634. {
  635. Debug.WriteLine("CMD SENT POLL CANCEL");
  636. commandResultCancellatonSource.Cancel();
  637. }
  638. }
  639. private void ListView_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
  640. {
  641. CommandSelected = null;
  642. if (e.AddedItems.Any())
  643. {
  644. var command = e.AddedItems[0] as Command;
  645. if (command != null)
  646. {
  647. CommandSelected = command;
  648. }
  649. }
  650. }
  651. }
  652. }