MobileDataGrid.xaml.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. using comal.timesheets.Data_Classes;
  2. using comal.timesheets.Deliveries;
  3. using InABox.Clients;
  4. using InABox.Core;
  5. using Syncfusion.XForms.PopupLayout;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Collections.ObjectModel;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Reflection;
  12. using Xamarin.Forms;
  13. using Xamarin.Forms.Xaml;
  14. namespace comal.timesheets
  15. {
  16. public enum DataGridSaveType
  17. {
  18. None,
  19. Single,
  20. Multiple
  21. }
  22. public delegate void DataGridOptionsSet(string title, DataGridSaveType savetype = DataGridSaveType.None);
  23. public delegate void DataGridItemSelected(DataGridViewModelItem item);
  24. [XamlCompilation(XamlCompilationOptions.Compile)]
  25. public partial class MobileDataGrid : ContentView
  26. {
  27. public event DataGridOptionsSet OnOptionsSet;
  28. public event DataGridItemSelected OnItemSelected;
  29. public List<DataGridViewModelItem> Items { get; set; }
  30. DataGridSaveType SaveType { get; set; }
  31. bool bSearching = false;
  32. ObservableCollection<DataGridFilter> Filters = new ObservableCollection<DataGridFilter>();
  33. List<DataGridViewModelItem> CurrentItems = new List<DataGridViewModelItem>();
  34. PropertyInfo[] info = typeof(DataGridViewModelItem).GetProperties();
  35. Dictionary<string, List<string>> FilterOptions = new Dictionary<string, List<string>>();
  36. Type Type;
  37. SfPopupLayout popupLayout;
  38. public MobileDataGrid()
  39. {
  40. InitializeComponent();
  41. Items = new List<DataGridViewModelItem>();
  42. Filters.CollectionChanged += Filters_CollectionChanged;
  43. popupLayout = new SfPopupLayout();
  44. popupLayout.PopupView.WidthRequest = 600;
  45. popupLayout.PopupView.HeightRequest = 600;
  46. popupLayout.PopupView.HeaderTitle = "Image";
  47. popupLayout.PopupView.AcceptButtonText = "Close";
  48. }
  49. #region Grid Setup
  50. public void Setup(List<DataGridViewModelItem> items, Type type, DataGridSaveType savetype = DataGridSaveType.None)
  51. {
  52. Type = type;
  53. Items = items;
  54. Device.BeginInvokeOnMainThread(() =>
  55. {
  56. SetupHeaders(items.First());
  57. Refresh(Items);
  58. });
  59. OnOptionsSet?.Invoke(type.Name, savetype);
  60. SaveType = savetype;
  61. }
  62. /// <summary>
  63. /// Never pass CurrentItems into this function - create an intermediate list first
  64. /// </summary>
  65. /// <param name="items"></param>
  66. private void Refresh(List<DataGridViewModelItem> items)
  67. {
  68. itemsListView.ItemsSource = items;
  69. countLbl.Text = items.Count + " Records";
  70. CurrentItems.Clear();
  71. foreach (var item in items)
  72. {
  73. CurrentItems.Add(item);
  74. }
  75. if (Filters.Any())
  76. filterBtnRow.Height = 80;
  77. else
  78. filterBtnRow.Height = 0;
  79. int count = 0;
  80. foreach (var column in Items.First().Data)
  81. {
  82. var filter = Filters.FirstOrDefault(x => x.ColNumber == "Col" + count);
  83. if (filter != null)
  84. ChangeHeaderColour(true, count);
  85. else
  86. ChangeHeaderColour(false, count);
  87. count++;
  88. }
  89. }
  90. public void SetupHeaders(DataGridViewModelItem item)
  91. {
  92. var count = GenerateHeaders(item);
  93. GenerateImageHeader(item, count);
  94. }
  95. public int GenerateHeaders(DataGridViewModelItem item)
  96. {
  97. int count = 0;
  98. foreach (var tuple in item.Data)
  99. {
  100. CreateNewHeader(tuple.Item1, count);
  101. CreateFilterOption(count);
  102. count++;
  103. }
  104. return count;
  105. }
  106. private void GenerateImageHeader(DataGridViewModelItem item, int count)
  107. {
  108. if (item.Image != null)
  109. {
  110. headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
  111. DataGridHeaderRow header = new DataGridHeaderRow { ColumnName = "Image", ColumnNumber = count };
  112. header.Setup();
  113. headerGrid.Children.Add(SetGridValues(header, 0, count));
  114. CreateSearchEntry("Image", count);
  115. }
  116. }
  117. private void CreateNewHeader(string name, int count)
  118. {
  119. headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
  120. DataGridHeaderRow header = new DataGridHeaderRow { ColumnName = name, ColumnNumber = count };
  121. header.Setup();
  122. header.OnDataGridHeaderFilterTapped += Header_OnDataGridHeaderFilterTapped;
  123. header.OnDataGridHeaderTapped += Header_OnDataGridHeaderTapped;
  124. headerGrid.Children.Add(SetGridValues(header, 0, count));
  125. CreateSearchEntry(name, count);
  126. }
  127. private void CreateFilterOption(int column)
  128. {
  129. List<string> options = new List<string>();
  130. foreach (var property in info)
  131. {
  132. if (property.Name == "Col" + column)
  133. foreach (var item in Items)
  134. {
  135. string value = GetStringValue(property, item);
  136. if (!options.Contains(value) && !string.IsNullOrWhiteSpace(value))
  137. options.Add(value);
  138. }
  139. }
  140. options.Sort();
  141. FilterOptions.Add("Col" + column, options);
  142. }
  143. private void CreateSearchEntry(string name, int count)
  144. {
  145. var searchEnt = new DataGridSearchEntry(name, count);
  146. searchEnt.OnDataGridSearchEntryChanged += SearchEnt_OnDataGridSearchEntryChanged;
  147. searchEnt.IsEnabled = name == "Image" ? false : true;
  148. headerGrid.Children.Add(SetGridValues(searchEnt, 1, count));
  149. }
  150. private View SetGridValues(View view, int row, int column)
  151. {
  152. view.SetValue(Grid.RowProperty, row);
  153. view.SetValue(Grid.ColumnProperty, column);
  154. return view;
  155. }
  156. #endregion
  157. #region Events
  158. private void Row_Tapped(object sender, EventArgs e)
  159. {
  160. var item = itemsListView.SelectedItem as DataGridViewModelItem;
  161. if (item == null)
  162. return;
  163. if (SaveType != DataGridSaveType.None)
  164. {
  165. switch (SaveType)
  166. {
  167. case DataGridSaveType.Single:
  168. AddSelectionToLists(item);
  169. UnselectOthers(item);
  170. break;
  171. case DataGridSaveType.Multiple:
  172. AddSelectionToLists(item);
  173. break;
  174. }
  175. List<DataGridViewModelItem> list = new List<DataGridViewModelItem>();
  176. foreach (var i in CurrentItems)
  177. list.Add(i);
  178. Refresh(list);
  179. }
  180. else if (SaveType == DataGridSaveType.None)
  181. {
  182. OnItemSelected?.Invoke(item);
  183. }
  184. }
  185. private void UnselectOthers(DataGridViewModelItem item)
  186. {
  187. UnselectItems(item, Items);
  188. UnselectItems(item, CurrentItems);
  189. }
  190. private void Image_Tapped(object sender, EventArgs e)
  191. {
  192. var item = ((TappedEventArgs)e).Parameter as DataGridViewModelItem;
  193. if (item == null)
  194. return;
  195. if (item.ImageID == Guid.Empty)
  196. return;
  197. CoreTable table = new Client<Document>().Query(new Filter<Document>(x => x.ID).IsEqualTo(item.ImageID),
  198. new Columns<Document>(x => x.Data));
  199. CoreRow docrow = table.Rows.FirstOrDefault();
  200. if (docrow != null)
  201. {
  202. byte[] data = docrow.Get<Document, byte[]>(x => x.Data);
  203. ImageSource src = ImageSource.FromStream(() => new MemoryStream(data));
  204. if (src != null)
  205. {
  206. Image popupContent = new Image();
  207. popupContent.HorizontalOptions = LayoutOptions.FillAndExpand;
  208. popupContent.VerticalOptions = LayoutOptions.FillAndExpand;
  209. popupContent.Aspect = Aspect.AspectFit;
  210. popupContent.Source = src;
  211. popupLayout.PopupView.ContentTemplate = new DataTemplate(() =>
  212. {
  213. return popupContent;
  214. });
  215. Device.BeginInvokeOnMainThread(() => { popupLayout.Show(); });
  216. }
  217. }
  218. }
  219. private void UnselectItems(DataGridViewModelItem item, List<DataGridViewModelItem> selectedlist)
  220. {
  221. var list = selectedlist.Where(x => x.IsSelected == true);
  222. foreach (var foundItem in list)
  223. {
  224. if (foundItem.ID != item.ID)
  225. foundItem.IsSelected = false;
  226. }
  227. }
  228. private void AddSelectionToLists(DataGridViewModelItem item)
  229. {
  230. bool selected = item.IsSelected;
  231. AddSelectionToList(selected, Items, item.ID);
  232. AddSelectionToList(selected, CurrentItems, item.ID);
  233. }
  234. private void AddSelectionToList(bool selected, List<DataGridViewModelItem> list, Guid ID)
  235. {
  236. var foundItem = list.FirstOrDefault(x => x.ID == ID);
  237. if (foundItem != null)
  238. foundItem.IsSelected = selected ? false : true;
  239. }
  240. private void SearchEnt_OnDataGridSearchEntryChanged(int columnnumber, string value, string colname)
  241. {
  242. if (string.IsNullOrWhiteSpace(value))
  243. Filters.Remove(Filters.FirstOrDefault(x => x.ColNumber == "Col" + columnnumber && x.FilterType == FilterType.Typed));
  244. else
  245. {
  246. if (Filters.FirstOrDefault(x => x.ColNumber == "Col" + columnnumber) != null)
  247. Filters.Remove(Filters.FirstOrDefault(x => x.ColNumber == "Col" + columnnumber && x.FilterType == FilterType.Typed));
  248. Filters.Add(new DataGridFilter(colname, "Col" + columnnumber, value, FindNumber(columnnumber), FilterType.Typed));
  249. }
  250. }
  251. private void Filters_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
  252. {
  253. if (bSearching)
  254. return;
  255. CheckFilterDisplay();
  256. bSearching = true;
  257. List<DataGridViewModelItem> finalList = new List<DataGridViewModelItem>();
  258. if (Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.Zero) != null)
  259. {
  260. var foundfilters = Filters.Where(x => x.FilterNumber == FilterNumber.Zero);
  261. foreach (var foundfilter in foundfilters)
  262. {
  263. foreach (DataGridViewModelItem item in RunSearch(Items, foundfilter.Value, "Col0"))
  264. finalList.Add(item);
  265. }
  266. }
  267. else
  268. {
  269. foreach (DataGridViewModelItem item in Items)
  270. finalList.Add(item);
  271. }
  272. if (Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.One) != null)
  273. {
  274. var foundfilters = Filters.Where(x => x.FilterNumber == FilterNumber.One);
  275. List<DataGridViewModelItem> intermediatelist = new List<DataGridViewModelItem>();
  276. foreach (var foundfilter in foundfilters)
  277. {
  278. foreach (DataGridViewModelItem item in RunSearch(finalList, foundfilter.Value, "Col1"))
  279. intermediatelist.Add(item);
  280. }
  281. finalList.Clear();
  282. foreach (DataGridViewModelItem item in intermediatelist)
  283. finalList.Add(item);
  284. }
  285. else if (finalList.Count == 0)
  286. {
  287. foreach (DataGridViewModelItem item in Items)
  288. finalList.Add(item);
  289. }
  290. if (Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.Two) != null)
  291. {
  292. var foundfilters = Filters.Where(x => x.FilterNumber == FilterNumber.Two);
  293. List<DataGridViewModelItem> intermediatelist = new List<DataGridViewModelItem>();
  294. foreach (var foundfilter in foundfilters)
  295. {
  296. foreach (DataGridViewModelItem item in RunSearch(finalList, foundfilter.Value, "Col2"))
  297. intermediatelist.Add(item);
  298. }
  299. finalList.Clear();
  300. foreach (DataGridViewModelItem item in intermediatelist)
  301. finalList.Add(item);
  302. }
  303. else if (finalList.Count == 0)
  304. {
  305. foreach (DataGridViewModelItem item in Items)
  306. finalList.Add(item);
  307. }
  308. if (Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.Three) != null)
  309. {
  310. var foundfilters = Filters.Where(x => x.FilterNumber == FilterNumber.Three);
  311. List<DataGridViewModelItem> intermediatelist = new List<DataGridViewModelItem>();
  312. foreach (var foundfilter in foundfilters)
  313. {
  314. foreach (DataGridViewModelItem item in RunSearch(finalList, foundfilter.Value, "Col3"))
  315. intermediatelist.Add(item);
  316. }
  317. finalList.Clear();
  318. foreach (DataGridViewModelItem item in intermediatelist)
  319. finalList.Add(item);
  320. }
  321. if (finalList.Count == 0 && Filters.Count == 0)
  322. {
  323. foreach (DataGridViewModelItem item in Items)
  324. finalList.Add(item);
  325. }
  326. else if (finalList.Count == Items.Count && Filters.Count > 0)
  327. finalList.Clear();
  328. Refresh(finalList);
  329. bSearching = false;
  330. }
  331. private void CheckFilterDisplay()
  332. {
  333. filterLayout.Children.Clear();
  334. foreach (var filter in Filters)
  335. {
  336. DataGridFilterView filterview = new DataGridFilterView(filter.DisplayValue, filter.FilterType, filter.ColNumber);
  337. filterview.OnFilterClosed += Filterview_OnFilterClosed;
  338. filterLayout.Children.Add(filterview);
  339. }
  340. }
  341. private void Filterview_OnFilterClosed(string value, FilterType type, string colnumber)
  342. {
  343. List<DataGridFilter> toRemove = new List<DataGridFilter>();
  344. foreach (var child in filterLayout.Children)
  345. {
  346. if (child.GetType() == typeof(DataGridFilterView))
  347. {
  348. if ((child as DataGridFilterView).Value == value && (child as DataGridFilterView).FilterType == type)
  349. {
  350. var filter = Filters.FirstOrDefault(x => x.DisplayValue == value && x.FilterType == type);
  351. if (filter != null)
  352. toRemove.Add(filter);
  353. }
  354. }
  355. }
  356. if (toRemove.First().FilterType == FilterType.Typed)
  357. {
  358. foreach (var child in headerGrid.Children)
  359. {
  360. if (child.GetType() == typeof(DataGridSearchEntry))
  361. {
  362. if ((child as DataGridSearchEntry).ColumnNumber == int.Parse(colnumber.Substring(3, 1)))
  363. (child as DataGridSearchEntry).Text = "";
  364. }
  365. }
  366. }
  367. Filters.Remove(toRemove.First());
  368. }
  369. private void Header_OnDataGridHeaderTapped(int columnnumber, SearchUtils.SortDirection sortdirection)
  370. {
  371. var intermediatelist = new List<DataGridViewModelItem>();
  372. foreach (var property in info)
  373. {
  374. if (property.Name == "Col" + columnnumber)
  375. {
  376. foreach (var item in SearchUtils.OrderByPropertyName(CurrentItems, "Col" + columnnumber, sortdirection))
  377. {
  378. intermediatelist.Add(item);
  379. }
  380. Refresh(intermediatelist);
  381. }
  382. }
  383. }
  384. private void Header_OnDataGridHeaderFilterTapped(int columnnumber, string columnname)
  385. {
  386. List<string> options = FilterOptions["Col" + columnnumber];
  387. List<DataGridFilter> filters = new List<DataGridFilter>();
  388. var selectedFilters = Filters.Where(x => x.FilterType == FilterType.Selected && x.ColNumber == "Col" + columnnumber);
  389. foreach (var list in selectedFilters)
  390. {
  391. filters.Add(list);
  392. }
  393. MultiSelectPage filterpage = new MultiSelectPage(options, filters, columnnumber, columnname);
  394. filterpage.OnPageSaved += FilterPage_OnPageSaved;
  395. Navigation.PushAsync(filterpage);
  396. }
  397. private void FilterPage_OnPageSaved(IEnumerable<MultiSelectPageViewItem> items, int columnnumber, string columnname)
  398. {
  399. var intermediateList = new List<DataGridFilter>();
  400. var list = Filters.Where(x => x.ColNumber == "Col" + columnnumber && x.FilterType == FilterType.Selected);
  401. foreach (var item in list)
  402. {
  403. intermediateList.Add(item);
  404. }
  405. foreach (var filter in intermediateList)
  406. Filters.Remove(filter);
  407. foreach (var item in items)
  408. Filters.Add(new DataGridFilter(columnname, "Col" + columnnumber, item.Value, FindNumber(columnnumber), FilterType.Selected));
  409. var newlist = Filters.Where(x => x.ColNumber == "Col" + columnnumber);
  410. }
  411. #endregion
  412. #region Utils
  413. private IEnumerable<DataGridViewModelItem> RunSearch(IEnumerable<DataGridViewModelItem> list, string value, string propertyname)
  414. {
  415. var intermediatelist = new List<DataGridViewModelItem>();
  416. foreach (var property in info)
  417. {
  418. if (property.Name == propertyname)
  419. {
  420. foreach (var item in list)
  421. {
  422. if (GetStringValue(property, item).Contains(value)
  423. || GetStringValue(property, item).Contains(value.ToUpper())
  424. || GetStringValue(property, item).Contains(value.ToLower())
  425. || GetStringValue(property, item).Contains(SearchUtils.LowerCaseFirst(value))
  426. || GetStringValue(property, item).Contains(SearchUtils.UpperCaseFirst(value))
  427. || GetStringValue(property, item).Contains(SearchUtils.UpperCaseSecond(value))
  428. )
  429. {
  430. if (!intermediatelist.Contains(item))
  431. intermediatelist.Add(item);
  432. }
  433. }
  434. }
  435. }
  436. return intermediatelist;
  437. }
  438. private void ChangeHeaderColour(bool filterpresent, int colnumber)
  439. {
  440. foreach (var header in headerGrid.Children)
  441. {
  442. if (header.GetType() == typeof(DataGridHeaderRow))
  443. {
  444. if ((header as DataGridHeaderRow).ColumnNumber == colnumber)
  445. (header as DataGridHeaderRow).ChangeFilterColour(filterpresent);
  446. }
  447. }
  448. }
  449. private string GetStringValue(PropertyInfo property, object item)
  450. {
  451. if (property.PropertyType == typeof(string))
  452. return (string)property.GetValue(item);
  453. else
  454. return "";
  455. }
  456. private FilterNumber FindNumber(int columnnumber)
  457. {
  458. switch (columnnumber)
  459. {
  460. case 0:
  461. return FilterNumber.Zero;
  462. case 1:
  463. return FilterNumber.One;
  464. case 2:
  465. return FilterNumber.Two;
  466. case 3:
  467. return FilterNumber.Three;
  468. default:
  469. return FilterNumber.Zero;
  470. }
  471. }
  472. #endregion
  473. }
  474. public enum FilterNumber
  475. {
  476. Zero,
  477. One,
  478. Two,
  479. Three
  480. }
  481. public enum FilterType
  482. {
  483. Typed,
  484. Selected
  485. }
  486. public class DataGridFilter
  487. {
  488. public string ColNumber { get; set; }
  489. public string ColName { get; set; }
  490. public string Value { get; set; }
  491. public FilterNumber FilterNumber { get; set; }
  492. public FilterType FilterType { get; set; }
  493. public string DisplayValue
  494. {
  495. get => ColName + " = " + Value;
  496. }
  497. public DataGridFilter(string colname, string colNumber, string value, FilterNumber filterNumber, FilterType filterType)
  498. {
  499. ColName = colname;
  500. ColNumber = colNumber;
  501. Value = value;
  502. FilterNumber = filterNumber;
  503. FilterType = filterType;
  504. }
  505. }
  506. public class DataGridViewModelItem
  507. {
  508. public Guid ID { get; set; }
  509. public Guid ImageID { get; set; }
  510. private bool isSelected;
  511. public bool IsSelected
  512. {
  513. get
  514. {
  515. return isSelected;
  516. }
  517. set
  518. {
  519. isSelected = value;
  520. Color = isSelected == true ? Color.FromHex("#91a3b0") /*Cadet Gray*/ : Color.Default;
  521. }
  522. }
  523. public Color Color { get; set; }
  524. public List<Tuple<string, string>> Data { get; set; }
  525. public string Col0 { get; set; }
  526. public string Col1 { get; set; }
  527. public string Col2 { get; set; }
  528. public string Col3 { get; set; }
  529. public Image Image { get; set; }
  530. public ImageSource Source
  531. {
  532. get
  533. {
  534. return Image == null? null: Image.Source;
  535. }
  536. }
  537. public GridLength ColWidth0 { get; set; }
  538. public GridLength ColWidth1 { get; set; }
  539. public GridLength ColWidth2 { get; set; }
  540. public GridLength ColWidth3 { get; set; }
  541. public GridLength ImageColWidth { get; set; }
  542. public bool ImageColVisible { get; set; }
  543. public DataGridViewModelItem(Guid id, List<Tuple<string, string>> data, Image image = null, Guid imageid = new Guid())
  544. {
  545. ID = id;
  546. ImageID = imageid;
  547. Data = data;
  548. Image = image;
  549. Col0 = data.Count > 0 ? data[0].Item2 : "";
  550. Col1 = data.Count > 1 ? data[1].Item2 : "";
  551. Col2 = data.Count > 2 ? data[2].Item2 : "";
  552. Col3 = data.Count > 3 ? data[3].Item2 : "";
  553. ImageColWidth = image != null ? new GridLength(0.5, GridUnitType.Star) : new GridLength(0, GridUnitType.Absolute);
  554. ImageColVisible = image != null ? true : false;
  555. ColWidth0 = data.Count > 0 ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Absolute);
  556. ColWidth1 = data.Count > 1 ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Absolute);
  557. ColWidth2 = data.Count > 2 ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Absolute);
  558. ColWidth3 = data.Count > 3 ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Absolute);
  559. IsSelected = false;
  560. }
  561. }
  562. }