MobileDataGrid.xaml.cs 19 KB

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