MobileToolGrid.xaml.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7. using InABox.Core;
  8. using Syncfusion.Data.Extensions;
  9. using Xamarin.Essentials;
  10. using Xamarin.Forms;
  11. using Xamarin.Forms.Xaml;
  12. using XF.Material.Forms;
  13. namespace InABox.Mobile
  14. {
  15. public class ToolGridLayoutChangedEventArgs : EventArgs
  16. {
  17. public int RowCount { get; private set; }
  18. public int ColCount { get; private set; }
  19. public ToolGridLayoutChangedEventArgs(int rowcount, int colcount)
  20. {
  21. RowCount = rowcount;
  22. ColCount = colcount;
  23. }
  24. }
  25. public delegate void ToolGridLayoutChangedEvent(object sender, ToolGridLayoutChangedEventArgs args);
  26. public class ToolGridViewModel : BindableObject
  27. {
  28. public CoreObservableCollection<IMobileToolItem> Items { get; private set; }
  29. public CoreObservableCollection<IMobileToolItem> VisibleItems { get; private set; }
  30. public int Columns { get; set; }
  31. private bool _disableUpdate = false;
  32. public void BeginUpdate()
  33. => _disableUpdate = true;
  34. public void EndUpdate()
  35. {
  36. _disableUpdate = false;
  37. Refresh();
  38. }
  39. public ToolGridViewModel()
  40. {
  41. Columns = Device.Idiom == TargetIdiom.Tablet ? 6 : 4;
  42. VisibleItems = new CoreObservableCollection<IMobileToolItem>();
  43. Items = new CoreObservableCollection<IMobileToolItem>();
  44. Items.CollectionChanged += (sender, args) =>
  45. {
  46. if (args.OldItems != null)
  47. {
  48. foreach (var item in args.OldItems?.OfType<MobileToolItem>())
  49. item.VisibleChanged -= ItemChanged;
  50. }
  51. if (args.NewItems != null)
  52. {
  53. foreach (var item in args.NewItems.OfType<MobileToolItem>())
  54. item.VisibleChanged += ItemChanged;
  55. }
  56. Refresh();
  57. };
  58. }
  59. private void ItemChanged(object sender, EventArgs e)
  60. => Refresh();
  61. public void Refresh()
  62. {
  63. if (_disableUpdate)
  64. return;
  65. VisibleItems.Clear();
  66. VisibleItems.AddRange(Items.Where(x => x.IsVisible).ToArray());
  67. int iRow = 0;
  68. int iCol = 0;
  69. bool bDirty = false;
  70. foreach (var item in VisibleItems)
  71. {
  72. bDirty = iRow != item.Row || iCol != item.Column;
  73. item.Row = iRow;
  74. item.Column = iCol;
  75. iCol++;
  76. if (iCol == Columns)
  77. {
  78. iRow++;
  79. iCol = 0;
  80. }
  81. }
  82. if (bDirty)
  83. LayoutChanged?.Invoke(this,new ToolGridLayoutChangedEventArgs(iRow,Columns));
  84. }
  85. public Color BackgroundColor { get; set; }
  86. public event ToolGridLayoutChangedEvent LayoutChanged;
  87. }
  88. [XamlCompilation(XamlCompilationOptions.Compile)]
  89. public partial class MobileToolGrid
  90. {
  91. public IList<IMobileToolItem> Items => _viewModel.Items;
  92. public event EventHandler BeforeTap;
  93. public event EventHandler AfterTap;
  94. private ToolGridViewModel _viewModel = new();
  95. public void BeginUpdate()
  96. {
  97. _viewModel?.BeginUpdate();
  98. }
  99. public void EndUpdate()
  100. {
  101. _viewModel.EndUpdate();
  102. }
  103. public MobileToolGrid()
  104. {
  105. _viewModel.LayoutChanged += _viewModel_OnLayoutChanged;
  106. BeginUpdate();
  107. InitializeComponent();
  108. EndUpdate();
  109. }
  110. public void Refresh()
  111. {
  112. _viewModel.Refresh();
  113. }
  114. private readonly BindableProperty BorderColorProperty = BindableProperty.Create(
  115. nameof(BorderColor),
  116. typeof(Color),
  117. typeof(MobileToolGrid),
  118. Material.Color.SecondaryVariant
  119. );
  120. public Color BorderColor
  121. {
  122. get => (Color)GetValue(BorderColorProperty);
  123. set => SetValue(BorderColorProperty, value);
  124. }
  125. private bool debounce = false;
  126. private async void ToolItem_Tapped(object sender, EventArgs e)
  127. {
  128. if (debounce)
  129. return;
  130. debounce = true;
  131. BeforeTap?.Invoke(this, EventArgs.Empty);
  132. try
  133. {
  134. if ((sender is Frame frame) && (frame.BindingContext is MobileToolItem item) && item.IsEnabled)
  135. {
  136. frame.Scale = 0.5;
  137. await frame.ScaleTo(1, 150);
  138. item.DoTap();
  139. }
  140. }
  141. catch (Exception err)
  142. {
  143. MobileLogging.Log(err,"MobileToolGrid");
  144. }
  145. AfterTap?.Invoke(this, EventArgs.Empty);
  146. debounce = false;
  147. }
  148. private void _viewModel_OnLayoutChanged(object sender, ToolGridLayoutChangedEventArgs args)
  149. {
  150. _flexgrid.RowDefinitions.Clear();
  151. for (int i=0; i< args.RowCount; i++)
  152. _flexgrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto});
  153. _flexgrid.ColumnDefinitions.Clear();
  154. for (int i=0; i< args.ColCount; i++)
  155. _flexgrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star});
  156. BindableLayout.SetItemsSource(_flexgrid, null);
  157. BindableLayout.SetItemsSource(_flexgrid, _viewModel.VisibleItems);
  158. }
  159. }
  160. }