DynamicGridGridUIComponent.cs 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447
  1. using InABox.Clients;
  2. using InABox.Core;
  3. using InABox.WPF;
  4. using org.omg.PortableInterceptor;
  5. using Syncfusion.Data;
  6. using Syncfusion.UI.Xaml.Grid;
  7. using Syncfusion.UI.Xaml.Grid.Cells;
  8. using Syncfusion.UI.Xaml.Grid.Helpers;
  9. using Syncfusion.UI.Xaml.ScrollAxis;
  10. using Syncfusion.Windows.Shared;
  11. using System;
  12. using System.Collections.Generic;
  13. using System.Collections.ObjectModel;
  14. using System.ComponentModel;
  15. using System.Data;
  16. using System.Diagnostics.CodeAnalysis;
  17. using System.Linq;
  18. using System.Text;
  19. using System.Threading.Tasks;
  20. using System.Windows;
  21. using System.Windows.Controls;
  22. using System.Windows.Data;
  23. using System.Windows.Input;
  24. using System.Windows.Media;
  25. using System.Windows.Media.Imaging;
  26. using System.Windows.Threading;
  27. using DataRow = System.Data.DataRow;
  28. namespace InABox.DynamicGrid;
  29. public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynamicGridGridUIComponent<T>
  30. where T : BaseObject, new()
  31. {
  32. private readonly Dictionary<string, string> _filterpredicates = new();
  33. private Dictionary<string, CoreTable> Lookups = new();
  34. private IDynamicGridUIComponentParent<T> _parent;
  35. public IDynamicGridUIComponentParent<T> Parent
  36. {
  37. get => _parent;
  38. set
  39. {
  40. _parent = value;
  41. CellBackgroundConverter = new DynamicGridCellStyleConverter<System.Windows.Media.Brush?>(Parent, GetCellBackground);
  42. CellForegroundConverter = new DynamicGridCellStyleConverter<System.Windows.Media.Brush?>(Parent, GetCellForeground);
  43. CellFontSizeConverter = new DynamicGridCellStyleConverter<double?>(Parent, GetCellFontSize);
  44. CellFontStyleConverter = new DynamicGridCellStyleConverter<System.Windows.FontStyle?>(Parent, GetCellFontStyle);
  45. CellFontWeightConverter = new DynamicGridCellStyleConverter<System.Windows.FontWeight?>(Parent, GetCellFontWeight);
  46. DataGrid.RowStyleSelector = Parent.RowStyleSelector;
  47. DataGrid.TableSummaryCellStyleSelector = new DynamicGridSummaryStyleSelector(Parent);
  48. }
  49. }
  50. FrameworkElement IDynamicGridUIComponent<T>.Control => DataGrid;
  51. #region IDynamicGridGridUIComponent
  52. IList<DynamicColumnBase> IDynamicGridGridUIComponent<T>.ColumnList => ColumnList;
  53. int IDynamicGridGridUIComponent<T>.RowHeight => (int)RowHeight;
  54. #endregion
  55. private readonly SfDataGrid DataGrid;
  56. private readonly ContextMenu ColumnsMenu;
  57. private readonly GridRowSizingOptions gridRowResizingOptions = new() { CanIncludeHiddenColumns = false, AutoFitMode = AutoFitMode.Default };
  58. /// <summary>
  59. /// <see langword="null"/> when <see cref="DataGrid.ItemsSource"/> is <see langword="null"/>, generally while the grid is refreshing its columns.
  60. /// </summary>
  61. private DataTable? DataGridItems => (DataGrid.ItemsSource as DataTable);
  62. private DynamicGridCellStyleConverter<System.Windows.Media.Brush?> CellBackgroundConverter;
  63. private DynamicGridCellStyleConverter<System.Windows.Media.Brush?> CellForegroundConverter;
  64. private DynamicGridCellStyleConverter<double?> CellFontSizeConverter;
  65. private DynamicGridCellStyleConverter<System.Windows.FontStyle?> CellFontStyleConverter;
  66. private DynamicGridCellStyleConverter<System.Windows.FontWeight?> CellFontWeightConverter;
  67. public DynamicGridGridUIComponent()
  68. {
  69. ColumnsMenu = new ContextMenu();
  70. ColumnsMenu.Opened += ColumnsMenu_ContextMenuOpening;
  71. DataGrid = new SfDataGrid();
  72. DataGrid.VerticalAlignment = VerticalAlignment.Stretch;
  73. DataGrid.HorizontalAlignment = HorizontalAlignment.Stretch;
  74. DataGrid.HeaderContextMenu = ColumnsMenu;
  75. DataGrid.CellTapped += DataGrid_CellTapped;
  76. DataGrid.CellDoubleTapped += DataGrid_CellDoubleTapped;
  77. DataGrid.SelectionChanging += DataGrid_SelectionChanging;
  78. DataGrid.SelectionChanged += DataGrid_SelectionChanged;
  79. DataGrid.SelectionMode = GridSelectionMode.Extended;
  80. DataGrid.SelectionUnit = GridSelectionUnit.Row;
  81. DataGrid.CanMaintainScrollPosition = true;
  82. DataGrid.SummaryCalculationUnit = SummaryCalculationUnit.AllRows;
  83. DataGrid.LiveDataUpdateMode = LiveDataUpdateMode.AllowSummaryUpdate;
  84. DataGrid.NavigationMode = NavigationMode.Row;
  85. DataGrid.AllowEditing = false;
  86. DataGrid.EditTrigger = EditTrigger.OnTap;
  87. DataGrid.CurrentCellBeginEdit += DataGrid_CurrentCellBeginEdit;
  88. DataGrid.CurrentCellEndEdit += DataGrid_CurrentCellEndEdit;
  89. DataGrid.CurrentCellValueChanged += DataGrid_CurrentCellValueChanged;
  90. DataGrid.CurrentCellDropDownSelectionChanged += DataGrid_CurrentCellDropDownSelectionChanged;
  91. DataGrid.PreviewKeyUp += DataGrid_PreviewKeyUp;
  92. DataGrid.BorderBrush = new SolidColorBrush(Colors.Gray);
  93. DataGrid.BorderThickness = new Thickness(0.75F);
  94. DataGrid.Background = new SolidColorBrush(Colors.DimGray);
  95. DataGrid.AutoGenerateColumns = false;
  96. DataGrid.ColumnSizer = GridLengthUnitType.AutoLastColumnFill;
  97. DataGrid.SelectionForegroundBrush = DynamicGridUtils.SelectionForeground;
  98. DataGrid.RowSelectionBrush = DynamicGridUtils.SelectionBackground;
  99. DataGrid.AllowDraggingRows = false;
  100. DataGrid.Drop += DataGrid_Drop;
  101. DataGrid.DragOver += DataGrid_DragOver;
  102. DataGrid.RowDragDropTemplate = TemplateGenerator.CreateDataTemplate(() =>
  103. {
  104. var border = new Border();
  105. border.Width = 100;
  106. border.Height = 100;
  107. border.BorderBrush = new SolidColorBrush(Colors.Firebrick);
  108. border.Background = new SolidColorBrush(Colors.Red);
  109. border.CornerRadius = new CornerRadius(5);
  110. return border;
  111. });
  112. DataGrid.CurrentCellBorderThickness = new Thickness(0);
  113. DataGrid.AllowFiltering = false;
  114. DataGrid.EnableDataVirtualization = true;
  115. DataGrid.RowHeight = 30;
  116. DataGrid.QueryRowHeight += DataGrid_QueryRowHeight;
  117. DataGrid.HeaderRowHeight = 30;
  118. DataGrid.MouseLeftButtonUp += DataGrid_MouseLeftButtonUp;
  119. DataGrid.MouseRightButtonUp += DataGrid_MouseRightButtonUp;
  120. DataGrid.KeyUp += DataGrid_KeyUp;
  121. DataGrid.PreviewGotKeyboardFocus += DataGrid_PreviewGotKeyboardFocus;
  122. //DataGrid.SelectionController = new GridSelectionControllerExt(DataGrid);
  123. DataGrid.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Visible);
  124. DataGrid.FilterChanged += DataGrid_FilterChanged;
  125. DataGrid.FilterItemsPopulating += DataGrid_FilterItemsPopulating;
  126. var fltstyle = new Style(typeof(GridFilterControl));
  127. fltstyle.Setters.Add(new Setter(GridFilterControl.FilterModeProperty, FilterMode.Both));
  128. fltstyle.Setters.Add(new Setter(GridFilterControl.SortOptionVisibilityProperty, Visibility.Collapsed));
  129. DataGrid.FilterPopupStyle = fltstyle;
  130. //DataGrid.MouseMove += DataGrid_MouseMove;
  131. DataGrid.CellToolTipOpening += DataGrid_CellToolTipOpening;
  132. //var headstyle = new Style(typeof(GridHeaderCellControl));
  133. //headstyle.Setters.Add(new Setter(GridHeaderCellControl.BackgroundProperty, new SolidColorBrush(Colors.WhiteSmoke)));
  134. //headstyle.Setters.Add(new Setter(GridHeaderCellControl.ForegroundProperty, new SolidColorBrush(Colors.Green)));
  135. //headstyle.Setters.Add(new Setter(GridHeaderCellControl.FontSizeProperty, 12.0F));
  136. //DataGrid.HeaderStyle = headstyle;
  137. DataGrid.SizeChanged += DataGrid_SizeChanged;
  138. }
  139. private void ColumnsMenu_ContextMenuOpening(object sender, RoutedEventArgs e)
  140. {
  141. if (sender is not ContextMenu menu) return;
  142. menu.Items.Clear();
  143. Parent.LoadColumnsMenu(menu);
  144. }
  145. #region Selection
  146. public CoreRow[] SelectedRows
  147. {
  148. get => GetSelectedRows();
  149. set => SetSelectedRows(value);
  150. }
  151. private CoreRow[] GetSelectedRows()
  152. {
  153. var result = new List<CoreRow>();
  154. foreach (var item in DataGrid.SelectedItems)
  155. {
  156. if (item is DataRowView datarow)
  157. {
  158. var row = datarow.Row.Table.Rows.IndexOf(datarow.Row);
  159. result.Add(Parent.Data.Rows[row]);
  160. }
  161. }
  162. return result.ToArray();
  163. }
  164. private void SetSelectedRows(CoreRow[] rows)
  165. {
  166. DataGrid.SelectedItems.Clear();
  167. var table = DataGridItems;
  168. if(table is null) return;
  169. var dataRows = rows.Where(x => x.Index > -1).Select(row =>
  170. {
  171. return table.Rows[row.Index];
  172. });
  173. if (!Parent.HasOption(DynamicGridOption.MultiSelect))
  174. {
  175. dataRows = dataRows.Take(1);
  176. }
  177. foreach (var row in dataRows)
  178. {
  179. var record = DataGrid.View?.Records.FirstOrDefault(x => (x.Data as DataRowView)!.Row == row);
  180. if(record?.Data is DataRowView rowView)
  181. {
  182. DataGrid.SelectedItems.Add(rowView);
  183. }
  184. }
  185. }
  186. private void DataGrid_SelectionChanging(object? sender, Syncfusion.UI.Xaml.Grid.GridSelectionChangingEventArgs e)
  187. {
  188. var cancel = new CancelEventArgs();
  189. Parent.BeforeSelection(cancel);
  190. if (cancel.Cancel)
  191. {
  192. e.Cancel = true;
  193. }
  194. }
  195. private void DataGrid_SelectionChanged(object? sender, GridSelectionChangedEventArgs e)
  196. {
  197. if(Parent.IsReady && !Parent.IsRefreshing)
  198. {
  199. StartTimer();
  200. }
  201. }
  202. private DispatcherTimer? clicktimer;
  203. private void StartTimer()
  204. {
  205. if (clicktimer is null)
  206. {
  207. clicktimer = new DispatcherTimer();
  208. clicktimer.Interval = TimeSpan.FromMilliseconds(200);
  209. clicktimer.Tick += (o, e) =>
  210. {
  211. clicktimer.IsEnabled = false;
  212. Parent.SelectItems(SelectedRows);
  213. };
  214. }
  215. clicktimer.IsEnabled = true;
  216. }
  217. private void StopTimer()
  218. {
  219. if (clicktimer is not null)
  220. clicktimer.IsEnabled = false;
  221. }
  222. #endregion
  223. public CoreRow[] GetVisibleRows()
  224. {
  225. var items = DataGrid.ItemsSource;
  226. var result = new List<CoreRow>();
  227. var table = DataGridItems;
  228. if (table is null) return Array.Empty<CoreRow>();
  229. var rows = DataGrid.View.Records.Select(x => (x.Data as DataRowView)!).ToList();
  230. foreach (var row in rows)
  231. {
  232. var iRow = table.Rows.IndexOf(row.Row);
  233. result.Add(Parent.Data.Rows[iRow]);
  234. }
  235. return result.ToArray();
  236. }
  237. private bool bFilterVisible;
  238. private void DataGrid_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
  239. {
  240. if (!DataGrid.IsEnabled)
  241. return;
  242. var visualContainer = DataGrid.GetVisualContainer();
  243. var rowcolumnindex = visualContainer.PointToCellRowColumnIndex(e.GetPosition(visualContainer));
  244. var columnindex = DataGrid.ResolveToGridVisibleColumnIndex(rowcolumnindex.ColumnIndex);
  245. var column = GetColumn(columnindex);
  246. if(column is not null)
  247. {
  248. Parent.OpenColumnMenu(column);
  249. }
  250. }
  251. private void DataGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  252. {
  253. if (!DataGrid.IsEnabled)
  254. return;
  255. var visualContainer = DataGrid.GetVisualContainer();
  256. var rowcolumnindex = visualContainer.PointToCellRowColumnIndex(e.GetPosition(visualContainer));
  257. var columnindex = DataGrid.ResolveToGridVisibleColumnIndex(rowcolumnindex.ColumnIndex);
  258. // Header Click Here!
  259. if (rowcolumnindex.RowIndex == 0)
  260. {
  261. var column = GetColumn(columnindex);
  262. if(column is DynamicActionColumn dac)
  263. {
  264. Parent.ExecuteActionColumn(dac, null);
  265. }
  266. }
  267. else if (!bFilterVisible)
  268. {
  269. StartTimer();
  270. }
  271. }
  272. private void DataGrid_CellTapped(object? sender, GridCellTappedEventArgs e)
  273. {
  274. if (!DataGrid.IsEnabled)
  275. return;
  276. if (GetColumn(e.RowColumnIndex.ColumnIndex) is DynamicActionColumn dac)
  277. {
  278. if(e.ChangedButton == MouseButton.Left || (e.ChangedButton == MouseButton.Right && dac is DynamicMenuColumn))
  279. {
  280. Parent.ExecuteActionColumn(dac, SelectedRows);
  281. }
  282. }
  283. else
  284. {
  285. StartTimer();
  286. }
  287. }
  288. private void DataGrid_KeyUp(object sender, KeyEventArgs e)
  289. {
  290. if (sender != DataGrid) return;
  291. Parent.HandleKey(e);
  292. }
  293. private void DataGrid_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
  294. {
  295. var bOld = bFilterVisible;
  296. if (e.NewFocus is GridFilterControl)
  297. bFilterVisible = true;
  298. else if (e.NewFocus is ScrollViewer || e.NewFocus is SfDataGrid)
  299. bFilterVisible = false;
  300. if (bOld && !bFilterVisible)
  301. {
  302. Parent.SelectItems(SelectedRows);
  303. }
  304. }
  305. // Please always use this function where possible!
  306. /// <summary>
  307. /// Get the <see cref="CoreRow"/> associated with a <paramref name="rowIndex"/> given from the Syncfusion DataGrid.
  308. /// </summary>
  309. /// <remarks>
  310. /// This is mandatory to use whenever we want the data associated with an index which Syncfusion has given us,
  311. /// because filtering and sorting will cause normal indexing operations to fail.
  312. /// </remarks>
  313. /// <param name="rowIndex"></param>
  314. /// <returns></returns>
  315. private CoreRow? GetRowFromIndex(int rowIndex)
  316. {
  317. // Syncfusion has given us the row index, so it also will give us the correct row, after sorting.
  318. // Hence, here we use the syncfusion DataGrid.GetRecordAtRowIndex, which *should* always return a DataRowView.
  319. var row = DataGrid.GetRecordAtRowIndex(rowIndex);
  320. if (row is not DataRowView dataRowView || DataGridItems is not DataTable table)
  321. return null;
  322. var rowIdx = table.Rows.IndexOf(dataRowView.Row);
  323. if (rowIdx < 0)
  324. return null;
  325. return Parent.Data.Rows[rowIdx];
  326. }
  327. private void DataGrid_CellDoubleTapped(object? sender, GridCellDoubleTappedEventArgs e)
  328. {
  329. StopTimer();
  330. Parent.DoubleClickCell(GetRowFromIndex(e.RowColumnIndex.RowIndex), GetColumn(e.RowColumnIndex.ColumnIndex));
  331. }
  332. public double RowHeight
  333. {
  334. get => DataGrid.RowHeight;
  335. set => DataGrid.RowHeight = value;
  336. }
  337. public double HeaderRowHeight
  338. {
  339. get => DataGrid.HeaderRowHeight;
  340. set => DataGrid.HeaderRowHeight = value;
  341. }
  342. private void DataGrid_QueryRowHeight(object? sender, QueryRowHeightEventArgs e)
  343. {
  344. if (e.RowIndex > 0)
  345. {
  346. e.Height = DataGrid.RowHeight;
  347. if (DataGrid.GridColumnSizer.GetAutoRowHeight(e.RowIndex, gridRowResizingOptions, out var autoHeight))
  348. if (autoHeight > DataGrid.RowHeight)
  349. e.Height = autoHeight;
  350. e.Handled = true;
  351. }
  352. }
  353. private void DataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
  354. {
  355. if (Parent.IsReady && !Parent.IsRefreshing)
  356. ResizeColumns(DataGrid, e.NewSize.Width - 2, e.NewSize.Height - 2);
  357. }
  358. public bool OptionsChanged()
  359. {
  360. ColumnsMenu.Visibility = Parent.HasOption(DynamicGridOption.SelectColumns) ? Visibility.Visible : Visibility.Hidden;
  361. var allowEditing = Parent.IsDirectEditMode();
  362. var reloadColumns = false;
  363. if (DataGrid.AllowEditing != allowEditing)
  364. {
  365. DataGrid.NavigationMode = allowEditing ? NavigationMode.Cell : NavigationMode.Row;
  366. DataGrid.AllowEditing = allowEditing;
  367. reloadColumns = true;
  368. }
  369. DataGrid.AllowFiltering = Parent.HasOption(DynamicGridOption.FilterRows);
  370. DataGrid.FilterRowPosition = Parent.HasOption(DynamicGridOption.FilterRows) ? FilterRowPosition.FixedTop : FilterRowPosition.None;
  371. if (Parent.HasOption(DynamicGridOption.DragSource))
  372. {
  373. if (!DataGrid.AllowDraggingRows)
  374. {
  375. DataGrid.AllowDraggingRows = true;
  376. DataGrid.RowDragDropController.DragStart += RowDragDropController_DragStart;
  377. }
  378. }
  379. else
  380. {
  381. if (DataGrid.AllowDraggingRows)
  382. {
  383. DataGrid.AllowDraggingRows = false;
  384. DataGrid.RowDragDropController.DragStart -= RowDragDropController_DragStart;
  385. }
  386. }
  387. DataGrid.AllowDrop = Parent.HasOption(DynamicGridOption.DragTarget);
  388. DataGrid.SelectionMode = Parent.HasOption(DynamicGridOption.MultiSelect) ? GridSelectionMode.Extended : GridSelectionMode.Single;
  389. return reloadColumns && DataGrid.Columns.Count > 0;
  390. }
  391. private void DataGrid_FilterChanged(object? o, GridFilterEventArgs e)
  392. {
  393. var col = DataGrid.Columns.IndexOf(e.Column);
  394. if (GetColumn(col) is DynamicActionColumn column)
  395. {
  396. if (e.FilterPredicates != null)
  397. {
  398. var filter = e.FilterPredicates.Select(x => x.FilterValue.ToString()!).ToArray();
  399. bool include = e.FilterPredicates.Any(x => x.FilterType == FilterType.Equals);
  400. column.SelectedFilters = include ? filter : (column.Filters ?? Enumerable.Empty<string>()).Except(filter).ToArray();
  401. }
  402. else
  403. column.SelectedFilters = Array.Empty<string>();
  404. DataGrid.ClearFilter(e.Column);
  405. //e.FilterPredicates?.Clear();
  406. //e.FilterPredicates?.Add(new FilterPredicate() { PredicateType = PredicateType.Or, FilterBehavior = Syncfusion.Data.FilterBehavior.StringTyped, FilterMode = ColumnFilter.DisplayText, FilterType = Syncfusion.Data.FilterType.NotEquals, FilterValue = "" });
  407. //e.FilterPredicates?.Add(new FilterPredicate() { PredicateType = PredicateType.Or, FilterBehavior = Syncfusion.Data.FilterBehavior.StringTyped, FilterMode = ColumnFilter.DisplayText, FilterType = Syncfusion.Data.FilterType.Equals, FilterValue = "" });
  408. Parent.Refresh(false, false);
  409. e.Handled = true;
  410. }
  411. if (e.FilterPredicates == null)
  412. {
  413. if (_filterpredicates.ContainsKey(e.Column.MappingName))
  414. _filterpredicates.Remove(e.Column.MappingName);
  415. }
  416. else
  417. {
  418. _filterpredicates[e.Column.MappingName] = Serialization.Serialize(e.FilterPredicates, true);
  419. }
  420. Parent.UIFilterChanged(this);
  421. UpdateRecordCount();
  422. }
  423. private void UpdateRecordCount()
  424. {
  425. var count = DataGrid.View != null ? DataGrid.View.Records.Count : Parent.Data.Rows.Count;
  426. Parent.UpdateRecordCount(count);
  427. }
  428. private void DataGrid_FilterItemsPopulating(object? sender, GridFilterItemsPopulatingEventArgs e)
  429. {
  430. var col = DataGrid.Columns.IndexOf(e.Column);
  431. if (GetColumn(col) is DynamicActionColumn column && column.Filters is not null)
  432. e.ItemsSource = column.Filters.Select(x => new FilterElement
  433. { DisplayText = x, ActualValue = x, IsSelected = column.SelectedFilters is null || column.SelectedFilters.Contains(x) });
  434. }
  435. private void DataGrid_CellToolTipOpening(object? sender, GridCellToolTipOpeningEventArgs e)
  436. {
  437. if (GetColumn(e.RowColumnIndex.ColumnIndex) is not DynamicActionColumn col)
  438. return;
  439. var toolTip = col.ToolTip;
  440. if (toolTip is null)
  441. return;
  442. var row = GetRowFromIndex(e.RowColumnIndex.RowIndex);
  443. e.ToolTip.Template = TemplateGenerator.CreateControlTemplate(
  444. typeof(ToolTip),
  445. () => toolTip.Invoke(col, row)
  446. );
  447. }
  448. public void AddVisualFilter(string column, string value, FilterType filtertype = FilterType.Contains)
  449. {
  450. if (string.IsNullOrWhiteSpace(value))
  451. return;
  452. var col = DataGrid.Columns.FirstOrDefault((x=>String.Equals(x.MappingName?.ToUpper(),column?.Replace(".", "_").ToUpper())));
  453. if (col != null)
  454. {
  455. col.FilterPredicates.Add(new FilterPredicate { FilterType = filtertype, FilterValue = value });
  456. col.FilteredFrom = FilteredFrom.FilterRow;
  457. }
  458. }
  459. public List<Tuple<string, Func<CoreRow, bool>>> GetFilterPredicates()
  460. {
  461. var list = new List<Tuple<string, Func<CoreRow, bool>>>();
  462. foreach (var column in DataGrid.Columns)
  463. {
  464. var colIndex = DataGrid.Columns.IndexOf(column);
  465. var col = ColumnList[colIndex];
  466. if (col is DynamicGridColumn gridColumn)
  467. {
  468. var rowPredicate = DynamicGridGridUIComponentExtension.ConvertColumnPredicates(gridColumn, column.FilterPredicates);
  469. if(rowPredicate is not null)
  470. {
  471. list.Add(new(gridColumn.ColumnName, rowPredicate));
  472. }
  473. }
  474. }
  475. return list;
  476. }
  477. public void ScrollIntoView(CoreRow row)
  478. {
  479. var rowIdx = DataGrid.ResolveToRowIndex(row.Index + 1);
  480. DataGrid.ScrollInView(new RowColumnIndex(rowIdx, 0));
  481. }
  482. protected virtual Brush? GetCellBackground(CoreRow row, DynamicColumnBase column) => null;
  483. protected virtual Brush? GetCellForeground(CoreRow row, DynamicColumnBase column) => null;
  484. protected virtual double? GetCellFontSize(CoreRow row, DynamicColumnBase column) => null;
  485. protected virtual FontStyle? GetCellFontStyle(CoreRow row, DynamicColumnBase column) => null;
  486. protected virtual FontWeight? GetCellFontWeight(CoreRow row, DynamicColumnBase column) => null;
  487. #region Columns
  488. private class StackedHeaderRenderer : GridStackedHeaderCellRenderer
  489. {
  490. private Style Style;
  491. public StackedHeaderRenderer()
  492. {
  493. var headstyle = new Style(typeof(GridStackedHeaderCellControl));
  494. headstyle.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  495. headstyle.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));
  496. headstyle.Setters.Add(new Setter(Control.FontSizeProperty, 12D));
  497. headstyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0.0, 0.0, 0, 0)));
  498. headstyle.Setters.Add(new Setter(Control.MarginProperty, new Thickness(0, 0, 0.75, 0.75)));
  499. Style = headstyle;
  500. }
  501. public override void OnInitializeEditElement(DataColumnBase dataColumn, GridStackedHeaderCellControl uiElement, object dataContext)
  502. {
  503. uiElement.Style = Style;
  504. base.OnInitializeEditElement(dataColumn, uiElement, dataContext);
  505. }
  506. }
  507. private void LoadStackedHeaders(DynamicGridColumnGroupings groupings)
  508. {
  509. DataGrid.StackedHeaderRows.Clear();
  510. foreach(var grouping in groupings)
  511. {
  512. var row = new StackedHeaderRow();
  513. var i = 0;
  514. foreach(var group in grouping.Groups)
  515. {
  516. var start = Math.Max(i, ColumnList.IndexOf(group.StartColumn));
  517. var end = Math.Max(start, ColumnList.IndexOf(group.EndColumn));
  518. if(end < start)
  519. {
  520. i = end + 1;
  521. continue;
  522. }
  523. var cols = Enumerable.Range(start, end - start + 1).Select(i => DataGrid.Columns[i]).ToArray();
  524. var stackedColumn = new StackedColumn
  525. {
  526. HeaderText = group.Header,
  527. ChildColumns = string.Join(',', cols.Select(x => x.MappingName))
  528. };
  529. row.StackedColumns.Add(stackedColumn);
  530. i = end + 1;
  531. }
  532. DataGrid.StackedHeaderRows.Add(row);
  533. }
  534. if(groupings.Count > 0)
  535. {
  536. DataGrid.CellRenderers.Remove("StackedHeader");
  537. DataGrid.CellRenderers.Add("StackedHeader", new StackedHeaderRenderer());
  538. }
  539. }
  540. private readonly List<DynamicColumnBase> ColumnList = new();
  541. private List<DynamicActionColumn> ActionColumns = new();
  542. private DynamicColumnBase? GetColumn(int index) =>
  543. index >= 0 && index < ColumnList.Count ? ColumnList[index] : null;
  544. int IDynamicGridUIComponent<T>.DesiredWidth()
  545. {
  546. return this.DesiredWidth();
  547. }
  548. private void ResizeColumns(SfDataGrid grid, double width, double height)
  549. {
  550. if (Parent.Data == null || width <= 0)
  551. return;
  552. grid.Dispatcher.BeginInvoke(() =>
  553. {
  554. foreach (var (index, size) in this.CalculateColumnSizes(width))
  555. DataGrid.Columns[index].Width = Math.Max(0.0F, size);
  556. });
  557. }
  558. private ObservableCollection<ISummaryColumn> Summaries = new();
  559. private void LoadActionColumns(DynamicActionColumnPosition position)
  560. {
  561. for (var i = 0; i < ActionColumns.Count; i++)
  562. {
  563. var column = ActionColumns[i];
  564. if (column.Position == position)
  565. {
  566. //String sColName = String.Format("ActionColumn{0}{1}", i, position == DynamicActionColumnPosition.Start ? "L" : "R");
  567. var sColName = string.Format("ActionColumn{0}", i);
  568. gridRowResizingOptions.ExcludeColumns.Add(sColName);
  569. var summary = column.Summary();
  570. if (summary != null)
  571. {
  572. summary.Name = sColName;
  573. summary.MappingName = sColName;
  574. Summaries.Add(summary);
  575. }
  576. if (column is DynamicImageColumn imgcol)
  577. {
  578. var newcol = new GridImageColumn();
  579. newcol.MappingName = sColName;
  580. //newcol.Stretch = Stretch.Uniform;
  581. newcol.Width = column.Width == 0 ? DataGrid.RowHeight : column.Width;
  582. newcol.Padding = new Thickness(4);
  583. newcol.ImageHeight = DataGrid.RowHeight - 8;
  584. newcol.ImageWidth = DataGrid.RowHeight - 8;
  585. newcol.ColumnSizer = GridLengthUnitType.None;
  586. newcol.HeaderText = column.HeaderText;
  587. newcol.AllowSorting = false;
  588. ApplyFilterStyle(newcol, true, true);
  589. newcol.ShowToolTip = column.ToolTip != null;
  590. newcol.ShowHeaderToolTip = column.ToolTip != null;
  591. var style = new Style();
  592. style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  593. style.Setters.Add(new Setter(Control.IsEnabledProperty, false));
  594. newcol.FilterRowCellStyle = style;
  595. var headstyle = new Style(typeof(GridHeaderCellControl));
  596. headstyle.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  597. headstyle.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));
  598. headstyle.Setters.Add(new Setter(Control.FontSizeProperty, 12D));
  599. if (!string.IsNullOrWhiteSpace(column.HeaderText))
  600. {
  601. //headstyle.Setters.Add(new Setter(LayoutTransformProperty, new RotateTransform(270.0F)));
  602. headstyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0.0, 0.0, 0, 0)));
  603. headstyle.Setters.Add(new Setter(Control.MarginProperty, new Thickness(0, 0, 0.75, 0.75)));
  604. if (imgcol.VerticalHeader)
  605. headstyle.Setters.Add(new Setter(Control.TemplateProperty,
  606. Application.Current.Resources["VerticalColumnHeader"] as ControlTemplate));
  607. }
  608. else
  609. {
  610. var image = imgcol.Image?.Invoke(null);
  611. if (image != null)
  612. {
  613. var template = new ControlTemplate(typeof(GridHeaderCellControl));
  614. var border = new FrameworkElementFactory(typeof(Border));
  615. border.SetValue(Border.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro));
  616. border.SetValue(Border.PaddingProperty, new Thickness(4));
  617. border.SetValue(Control.MarginProperty, new Thickness(0, 0, 1, 1));
  618. var img = new FrameworkElementFactory(typeof(Image));
  619. img.SetValue(Image.SourceProperty, image);
  620. border.AppendChild(img);
  621. template.VisualTree = border;
  622. headstyle.Setters.Add(new Setter(Control.TemplateProperty, template));
  623. }
  624. }
  625. newcol.HeaderStyle = headstyle;
  626. DataGrid.Columns.Add(newcol);
  627. ColumnList.Add(column);
  628. }
  629. else if (column is DynamicTextColumn txtCol)
  630. {
  631. var newcol = new GridTextColumn();
  632. gridRowResizingOptions.ExcludeColumns.Add(sColName);
  633. newcol.TextWrapping = TextWrapping.NoWrap;
  634. newcol.TextAlignment = txtCol.Alignment == Alignment.NotSet
  635. ? TextAlignment.Left
  636. : txtCol.Alignment == Alignment.BottomLeft || txtCol.Alignment == Alignment.MiddleLeft ||
  637. txtCol.Alignment == Alignment.TopLeft
  638. ? TextAlignment.Left
  639. : txtCol.Alignment == Alignment.BottomCenter || txtCol.Alignment == Alignment.MiddleCenter ||
  640. txtCol.Alignment == Alignment.TopCenter
  641. ? TextAlignment.Center
  642. : TextAlignment.Right;
  643. newcol.AllowEditing = false;
  644. newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged;
  645. newcol.MappingName = sColName;
  646. newcol.Width = column.Width;
  647. newcol.ColumnSizer = GridLengthUnitType.None;
  648. newcol.HeaderText = column.HeaderText;
  649. newcol.AllowFiltering = column.Filters != null && column.Filters.Any();
  650. newcol.AllowSorting = false;
  651. newcol.FilterRowOptionsVisibility = Visibility.Collapsed;
  652. newcol.ShowHeaderToolTip = column.ToolTip != null;
  653. var style = new Style();
  654. style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  655. style.Setters.Add(new Setter(Control.IsEnabledProperty, false));
  656. newcol.FilterRowCellStyle = style;
  657. var headstyle = new Style(typeof(GridHeaderCellControl));
  658. headstyle.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  659. headstyle.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));
  660. headstyle.Setters.Add(new Setter(Control.FontSizeProperty, 12D));
  661. headstyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0.0, 0.0, 0, 0)));
  662. headstyle.Setters.Add(new Setter(Control.MarginProperty, new Thickness(0, 0, 0.75, 0.75)));
  663. if (txtCol.VerticalHeader)
  664. {
  665. headstyle.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Left));
  666. headstyle.Setters.Add(new Setter(Control.TemplateProperty,
  667. Application.Current.Resources["VerticalColumnHeader"] as ControlTemplate));
  668. }
  669. newcol.HeaderStyle = headstyle;
  670. var cellstyle = new Style();
  671. cellstyle.Setters.Add(new Setter(Control.BackgroundProperty,
  672. new Binding()
  673. {
  674. Path = new PropertyPath("."), Converter = CellBackgroundConverter,
  675. ConverterParameter = column
  676. }));
  677. cellstyle.Setters.Add(new Setter(Control.ForegroundProperty,
  678. new Binding()
  679. { Converter = CellForegroundConverter, ConverterParameter = column }));
  680. cellstyle.Setters.Add(new Setter(Control.FontSizeProperty,
  681. new Binding()
  682. { Converter = CellFontSizeConverter, ConverterParameter = column }));
  683. cellstyle.Setters.Add(new Setter(Control.FontStyleProperty,
  684. new Binding()
  685. { Converter = CellFontStyleConverter, ConverterParameter = column }));
  686. cellstyle.Setters.Add(new Setter(Control.FontWeightProperty,
  687. new Binding()
  688. { Converter = CellFontWeightConverter, ConverterParameter = column }));
  689. newcol.CellStyle = cellstyle;
  690. DataGrid.Columns.Add(newcol);
  691. ColumnList.Add(column);
  692. }
  693. else if (column is DynamicTemplateColumn tmplCol)
  694. {
  695. var newcol = new GridTemplateColumn();
  696. newcol.CellTemplateSelector = new TemplateColumnSelector(this, tmplCol.Template);
  697. newcol.AllowEditing = false;
  698. newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged;
  699. newcol.MappingName = sColName;
  700. newcol.Width = tmplCol.Width;
  701. newcol.ColumnSizer = GridLengthUnitType.None;
  702. newcol.HeaderText = column.HeaderText;
  703. newcol.AllowFiltering = false;
  704. newcol.AllowSorting = false;
  705. newcol.FilterRowOptionsVisibility = Visibility.Collapsed;
  706. newcol.ShowToolTip = false;
  707. newcol.ShowHeaderToolTip = false;
  708. var style = new Style();
  709. style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  710. style.Setters.Add(new Setter(Control.IsEnabledProperty, false));
  711. newcol.FilterRowCellStyle = style;
  712. var headstyle = new Style(typeof(GridHeaderCellControl));
  713. headstyle.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  714. headstyle.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));
  715. headstyle.Setters.Add(new Setter(Control.FontSizeProperty, 12D));
  716. headstyle.Setters.Add(new Setter(Control.MarginProperty, new Thickness(0, 0, 0.75, 0.75)));
  717. headstyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0.0)));
  718. newcol.HeaderStyle = headstyle;
  719. var cellstyle = new Style();
  720. cellstyle.Setters.Add(new Setter(Control.BackgroundProperty,
  721. new Binding()
  722. {
  723. Path = new PropertyPath("."), Converter = CellBackgroundConverter,
  724. ConverterParameter = column
  725. }));
  726. cellstyle.Setters.Add(new Setter(Control.ForegroundProperty,
  727. new Binding()
  728. { Converter = CellForegroundConverter, ConverterParameter = column }));
  729. cellstyle.Setters.Add(new Setter(Control.FontSizeProperty,
  730. new Binding()
  731. { Converter = CellFontSizeConverter, ConverterParameter = column }));
  732. cellstyle.Setters.Add(new Setter(Control.FontStyleProperty,
  733. new Binding()
  734. { Converter = CellFontStyleConverter, ConverterParameter = column }));
  735. cellstyle.Setters.Add(new Setter(Control.FontWeightProperty,
  736. new Binding()
  737. { Converter = CellFontWeightConverter, ConverterParameter = column }));
  738. newcol.CellStyle = cellstyle;
  739. DataGrid.Columns.Add(newcol);
  740. ColumnList.Add(column);
  741. }
  742. }
  743. }
  744. }
  745. public class TemplateColumnSelector(DynamicGridGridUIComponent<T> parent, Func<CoreRow, FrameworkElement?> dataTemplate) : DataTemplateSelector
  746. {
  747. public Func<CoreRow, FrameworkElement?> DataTemplate { get; init; } = dataTemplate;
  748. public DynamicGridGridUIComponent<T> Parent { get; init; } = parent;
  749. public override DataTemplate? SelectTemplate(object item, DependencyObject container)
  750. {
  751. if (item is not DataRowView) return null;
  752. CoreRow? row;
  753. if(item is DataRowView view && Parent.DataGridItems is DataTable table)
  754. {
  755. var rowIdx = table.Rows.IndexOf(view.Row);
  756. if (rowIdx < 0)
  757. {
  758. row = null;
  759. }
  760. else
  761. {
  762. row = Parent.Parent.Data.Rows[rowIdx];
  763. }
  764. }
  765. else
  766. {
  767. row = null;
  768. }
  769. if (row is null) return null;
  770. return TemplateGenerator.CreateDataTemplate(() =>
  771. {
  772. return DataTemplate(row);
  773. });
  774. }
  775. }
  776. private void ApplyFilterStyle(GridColumn column, bool filtering, bool isactioncolumn)
  777. {
  778. var filterstyle = new Style();
  779. if (filtering)
  780. {
  781. filterstyle.Setters.Add(new Setter(Control.BackgroundProperty, DynamicGridUtils.FilterBackground));
  782. column.ImmediateUpdateColumnFilter = true;
  783. column.ColumnFilter = ColumnFilter.Value;
  784. column.FilterRowCondition = FilterRowCondition.Contains;
  785. column.FilterRowOptionsVisibility = Visibility.Collapsed;
  786. column.AllowBlankFilters = true;
  787. column.AllowSorting = isactioncolumn
  788. ? false
  789. : Parent.CanSort();
  790. }
  791. else
  792. {
  793. filterstyle.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  794. filterstyle.Setters.Add(new Setter(Control.IsEnabledProperty, false));
  795. column.ColumnFilter = ColumnFilter.Value;
  796. column.AllowFiltering = false;
  797. column.AllowSorting = false;
  798. column.FilterRowEditorType = "TextBox";
  799. column.FilterRowOptionsVisibility = Visibility.Collapsed;
  800. }
  801. column.FilterRowCellStyle = filterstyle;
  802. }
  803. private void LoadDataColumns(DynamicGridColumns columns)
  804. {
  805. foreach (var column in columns)
  806. {
  807. if (this.CreateEditorColumn(column, out var newcol, out var prop))
  808. {
  809. newcol.GetEntity = () => _editingObject.Object;
  810. newcol.EntityChanged += DoEntityChanged;
  811. if (!newcol.VariableHeight)
  812. gridRowResizingOptions.ExcludeColumns.Add(newcol.MappingName);
  813. var newColumn = newcol.CreateGridColumn();
  814. newColumn.AllowEditing = newcol.Editable && Parent.IsDirectEditMode();
  815. var summary = newcol.Summary();
  816. if (summary != null)
  817. Summaries.Add(summary);
  818. ApplyFilterStyle(newColumn, newcol.Filtered, false);
  819. var headstyle = new Style(typeof(GridHeaderCellControl));
  820. headstyle.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  821. headstyle.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));
  822. headstyle.Setters.Add(new Setter(Control.FontSizeProperty, 12D));
  823. newColumn.HeaderStyle = headstyle;
  824. var cellstyle = new Style();
  825. if (Parent.IsDirectEditMode())
  826. {
  827. if (prop.Editor is null || !prop.Editor.Editable.IsDirectEditable())
  828. {
  829. cellstyle.Setters.Add(new Setter(Control.BackgroundProperty,
  830. new SolidColorBrush(Colors.WhiteSmoke)));
  831. newColumn.AllowEditing = false;
  832. }
  833. else
  834. {
  835. cellstyle.Setters.Add(new Setter(Control.BackgroundProperty,
  836. new SolidColorBrush(Colors.LightYellow)));
  837. newColumn.AllowEditing = true;
  838. }
  839. cellstyle.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));
  840. newColumn.CellStyle = cellstyle;
  841. }
  842. else
  843. {
  844. cellstyle.Setters.Add(new Setter(Control.BackgroundProperty,
  845. new Binding()
  846. {
  847. Path = new PropertyPath("."), Converter = CellBackgroundConverter,
  848. ConverterParameter = column
  849. }));
  850. cellstyle.Setters.Add(new Setter(Control.ForegroundProperty,
  851. new Binding()
  852. { Converter = CellForegroundConverter, ConverterParameter = column }));
  853. cellstyle.Setters.Add(new Setter(Control.FontSizeProperty,
  854. new Binding()
  855. { Converter = CellFontSizeConverter, ConverterParameter = column }));
  856. cellstyle.Setters.Add(new Setter(Control.FontStyleProperty,
  857. new Binding()
  858. { Converter = CellFontStyleConverter, ConverterParameter = column }));
  859. cellstyle.Setters.Add(new Setter(Control.FontWeightProperty,
  860. new Binding()
  861. { Converter = CellFontWeightConverter, ConverterParameter = column }));
  862. newColumn.CellStyle = cellstyle;
  863. }
  864. DataGrid.Columns.Add(newColumn);
  865. ColumnList.Add(column);
  866. foreach (var extra in newcol.ExtraColumns)
  867. Parent.AddHiddenColumn(extra);
  868. }
  869. }
  870. }
  871. private void LoadSummaries()
  872. {
  873. if (Summaries.Any())
  874. {
  875. DataGrid.CellRenderers.Remove("TableSummary");
  876. DataGrid.CellRenderers.Add("TableSummary", new DynamicGridAggregateRenderer());
  877. DataGrid.TableSummaryRows.Add(new GridTableSummaryRow
  878. {
  879. ShowSummaryInRow = false,
  880. Position = TableSummaryRowPosition.Bottom,
  881. SummaryColumns = Summaries
  882. });
  883. }
  884. }
  885. public void RefreshColumns(DynamicGridColumns columns, DynamicActionColumns actionColumns, DynamicGridColumnGroupings groupings)
  886. {
  887. // Yo, please don't remove this.
  888. // The issue was when we were dynamically adding ActionColumns, and if we had to remove and then re-add them, we were getting massive performance hits
  889. // for no reason. I think perhaps the image columns were trying to refer to data that didn't exist anymore when calling DataGrid.Columns.Refresh(),
  890. // and thus some mega problems (perhaps even exceptions within Syncfusion) were occurring, and this seems to fix it.
  891. // I don't pretend to know why it works; this is probably the strangest problem I've ever come across.
  892. DataGrid.ItemsSource = null;
  893. DataGrid.Columns.Suspend();
  894. ColumnList.Clear();
  895. DataGrid.Columns.Clear();
  896. DataGrid.TableSummaryRows.Clear();
  897. gridRowResizingOptions.ExcludeColumns = new List<string>();
  898. ActionColumns = actionColumns.ToList();
  899. Summaries.Clear();
  900. LoadActionColumns(DynamicActionColumnPosition.Start);
  901. LoadDataColumns(columns);
  902. LoadActionColumns(DynamicActionColumnPosition.End);
  903. LoadSummaries();
  904. LoadStackedHeaders(groupings);
  905. DataGrid.Columns.Resume();
  906. DataGrid.RefreshColumns();
  907. foreach (var key in _filterpredicates.Keys.ToArray())
  908. if (DataGrid.Columns.Any(x => string.Equals(x.MappingName, key)))
  909. {
  910. var predicates = Serialization.Deserialize<List<FilterPredicate>>(_filterpredicates[key]);
  911. foreach (var predicate in predicates)
  912. {
  913. DataGrid.Columns[key].FilterPredicates.Add(predicate);
  914. DataGrid.Columns[key].FilteredFrom = FilteredFrom.FilterRow;
  915. }
  916. }
  917. else
  918. {
  919. _filterpredicates.Remove(key);
  920. }
  921. ResizeColumns(DataGrid, DataGrid.ActualWidth - 2, DataGrid.ActualHeight - 2);
  922. }
  923. #endregion
  924. #region Data
  925. public void BeforeRefresh()
  926. {
  927. DataGrid.SelectionForegroundBrush = DynamicGridUtils.SelectionForeground;
  928. DataGrid.RowSelectionBrush = DynamicGridUtils.SelectionBackground;
  929. }
  930. public void RefreshData(CoreTable data)
  931. {
  932. var defaults = new List<object?>();
  933. var result = new DataTable();
  934. foreach (var column in data.Columns)
  935. {
  936. var colname = column.ColumnName.Replace('.', '_');
  937. if (!result.Columns.Contains(colname))
  938. {
  939. result.Columns.Add(colname, column.DataType);
  940. if (!Parent.IsDirectEditMode())
  941. defaults.Add(column.DataType.GetDefault());
  942. }
  943. }
  944. for (var i = 0; i < ActionColumns.Count; i++)
  945. result.Columns.Add(string.Format("ActionColumn{0}", i),
  946. ActionColumns[i] is DynamicImageColumn
  947. ? typeof(BitmapImage)
  948. : typeof(String)
  949. );
  950. foreach (var row in data.Rows)
  951. {
  952. var newrow = result.NewRow();
  953. CoreRowToDataRow(newrow, row, defaults);
  954. result.Rows.Add(newrow);
  955. }
  956. //int rowIndex = DataGrid.SelectionController.CurrentCellManager.CurrentRowColumnIndex.RowIndex;
  957. //int columnIndex = DataGrid.SelectionController.CurrentCellManager.CurrentRowColumnIndex.ColumnIndex;
  958. //int scrollRowIndex = DataGrid.GetVisualContainer().ScrollRows.LastBodyVisibleLineIndex;
  959. DataGrid.ItemsSource = result;
  960. //this.DataGrid.ScrollInView(new Syncfusion.UI.Xaml.ScrollAxis.RowColumnIndex(scrollRowIndex, columnIndex));
  961. ResizeColumns(DataGrid, DataGrid.ActualWidth - 1, DataGrid.ActualHeight);
  962. UpdateRecordCount();
  963. }
  964. public void InvalidateRow(CoreRow row)
  965. {
  966. var table = DataGridItems;
  967. if(table is null)
  968. {
  969. return;
  970. }
  971. var rowdata = new List<object?>(row.Values);
  972. foreach (var ac in ActionColumns)
  973. rowdata.Add(ac.Data(row));
  974. var datarow = DataGridItems.Rows[row.Index];
  975. for (var i = 0; i < rowdata.Count; i++)
  976. datarow[i] = rowdata[i] ?? DBNull.Value;
  977. //datarow.ItemArray = rowdata.ToArray();
  978. }
  979. private void CoreRowToDataRow(DataRow newrow, CoreRow row, List<object?> defaults)
  980. {
  981. var rowdata = new List<object?>(row.Values);
  982. foreach (var ac in ActionColumns)
  983. rowdata.Add(ac.Data(row));
  984. try
  985. {
  986. var data = ProcessRow(rowdata, defaults).ToArray();
  987. newrow.ItemArray = data;
  988. }
  989. catch (Exception)
  990. {
  991. throw;
  992. }
  993. }
  994. private static IEnumerable<object?> ProcessRow(List<object?> values, List<object?> defaults)
  995. {
  996. if (defaults == null || !defaults.Any())
  997. return values;
  998. var result = new List<object?>();
  999. for (var i = 0; i < values.Count; i++)
  1000. {
  1001. var value = values[i];
  1002. var defaultvalue = i < defaults.Count ? defaults[i] : null;
  1003. result.Add(value == null || (value.Equals(defaultvalue) && !value.GetType().IsEnum) ? null : value);
  1004. }
  1005. return result;
  1006. }
  1007. #endregion
  1008. #region Direct Edit
  1009. private bool bChanged;
  1010. private class DirectEditingObject
  1011. {
  1012. public T Object { get; set; }
  1013. public CoreRow Row { get; set; }
  1014. public DataRow? DataRow { get; set; }
  1015. public DirectEditingObject(T obj, CoreRow row, DataRow? dataRow)
  1016. {
  1017. Object = obj;
  1018. Row = row;
  1019. DataRow = dataRow;
  1020. }
  1021. }
  1022. private DirectEditingObject? _editingObject;
  1023. private DirectEditingObject EnsureEditingObject(CoreRow row)
  1024. {
  1025. _editingObject ??= new(Parent.LoadItem(row), row, DataGridItems?.Rows[row.Index]);
  1026. return _editingObject;
  1027. }
  1028. private DataRow? GetDataRow(CoreRow row)
  1029. {
  1030. return DataGridItems?.Rows[row.Index];
  1031. }
  1032. void IDynamicGridUIComponent<T>.UpdateCell(CoreRow row, string column, object? value)
  1033. {
  1034. var dataRow = GetDataRow(row);
  1035. var datacolname = column.Replace(".", "_");
  1036. if(dataRow is not null)
  1037. {
  1038. dataRow[datacolname] = value ?? DBNull.Value;
  1039. }
  1040. }
  1041. void IDynamicGridUIComponent<T>.UpdateRow(CoreRow row)
  1042. {
  1043. var dataRow = GetDataRow(row);
  1044. if(dataRow is not null)
  1045. {
  1046. foreach(var (key, value) in row)
  1047. {
  1048. var datacolname = key.Replace(".", "_");
  1049. var dataValue = dataRow[datacolname];
  1050. if (!Equals(dataValue, value) && !(value is null && dataValue == DBNull.Value))
  1051. {
  1052. dataRow[datacolname] = value ?? DBNull.Value;
  1053. }
  1054. }
  1055. for (var i = 0; i < ActionColumns.Count; i++)
  1056. dataRow[$"ActionColumn{i}"] = ActionColumns[i].Data(row);
  1057. }
  1058. }
  1059. private void DoEntityChanged(IDynamicColumnBase column, DynamicColumnEntityChangedEventArgs args)
  1060. {
  1061. if (_editingObject is null) return;
  1062. Parent.EntityChanged(_editingObject.Object, _editingObject.Row, args.ColumnName, args.Changes);
  1063. }
  1064. private void UpdateData(string column, Dictionary<CoreColumn, object?> updates)
  1065. {
  1066. if (_editingObject is null)
  1067. return;
  1068. var coreRow = _editingObject.Row;
  1069. Parent.UpdateData(_editingObject.Object, coreRow, column, updates);
  1070. }
  1071. private void UpdateData(int rowIndex, int columnIndex)
  1072. {
  1073. var table = DataGridItems;
  1074. if (table is null)
  1075. return;
  1076. if (GetColumn(columnIndex) is DynamicGridColumn gridcol)
  1077. {
  1078. var datacol = Parent.Data.Columns.FirstOrDefault(x => x.ColumnName.Equals(gridcol.ColumnName));
  1079. if (datacol != null)
  1080. {
  1081. var datacolindex = Parent.Data.Columns.IndexOf(datacol);
  1082. var value = table.Rows[rowIndex][datacolindex];
  1083. if (value is DBNull)
  1084. value = CoreUtils.GetDefault(datacol.DataType);
  1085. UpdateData(datacol.ColumnName, new Dictionary<CoreColumn, object?>() { { datacol, value } });
  1086. }
  1087. }
  1088. }
  1089. private void DataGrid_CurrentCellBeginEdit(object? sender, CurrentCellBeginEditEventArgs e)
  1090. {
  1091. var table = DataGridItems;
  1092. var row = GetRowFromIndex(e.RowColumnIndex.RowIndex);
  1093. if (table is null || row is null)
  1094. return;
  1095. EnsureEditingObject(row);
  1096. var column = DataGrid.Columns[e.RowColumnIndex.ColumnIndex] as GridComboBoxColumn;
  1097. if (column != null && column.ItemsSource == null)
  1098. {
  1099. var colname = column.MappingName;
  1100. var colno = table.Columns.IndexOf(colname);
  1101. var property = Parent.Data.Columns[colno].ColumnName;
  1102. var prop = CoreUtils.GetProperty(typeof(T), property);
  1103. var editor = prop.GetEditor();
  1104. if (editor is ILookupEditor lookupEditor)
  1105. {
  1106. if (!Lookups.ContainsKey(property))
  1107. Lookups[property] = lookupEditor.Values(typeof(T), property);
  1108. var combo = column;
  1109. combo.ItemsSource = Lookups[property].ToDictionary(Lookups[property].Columns[0].ColumnName, "Display");
  1110. combo.SelectedValuePath = "Key";
  1111. combo.DisplayMemberPath = "Value";
  1112. }
  1113. }
  1114. bChanged = false;
  1115. }
  1116. private void DataGrid_CurrentCellValueChanged(object? sender, CurrentCellValueChangedEventArgs e)
  1117. {
  1118. var row = GetRowFromIndex(e.RowColumnIndex.RowIndex);
  1119. // Are we sure that this function is ever useful? It seems that since the data in the grid hasn't been updated by this point, this function is essentially useless (the data is updated in EndEdit). Probably need to check the GridCheckBoxColumn
  1120. if (row is null) return;
  1121. if (e.Column is GridCheckBoxColumn)
  1122. {
  1123. EnsureEditingObject(row);
  1124. }
  1125. if (_editingObject is not null)
  1126. UpdateData(_editingObject.Row.Index, e.RowColumnIndex.ColumnIndex);
  1127. if (e.Column is GridCheckBoxColumn)
  1128. _editingObject = null;
  1129. if (_editingObject is not null)
  1130. bChanged = true;
  1131. }
  1132. private void DataGrid_CurrentCellDropDownSelectionChanged(object? sender,
  1133. CurrentCellDropDownSelectionChangedEventArgs e)
  1134. {
  1135. var row = GetRowFromIndex(e.RowColumnIndex.RowIndex);
  1136. if (row is null)
  1137. return;
  1138. EnsureEditingObject(row);
  1139. if ((_editingObject is not null) && (e.SelectedItem is Tuple<object?, string> tuple))
  1140. {
  1141. var mappedname = DataGrid.Columns[e.RowColumnIndex.ColumnIndex].MappingName;
  1142. var colno = DataGridItems.Columns.IndexOf(mappedname);
  1143. var corecol = Parent.Data.Columns[colno].ColumnName;
  1144. var updates = new Dictionary<CoreColumn, object?>();
  1145. var prefix = String.Join(".", corecol.Split(".").Reverse().Skip(1).Reverse());
  1146. var field = corecol.Split(".").Last();
  1147. var prop = CoreUtils.GetProperty(typeof(T), corecol);
  1148. if (prop.GetEditor() is ILookupEditor editor)
  1149. {
  1150. var data = editor.Values(typeof(T), corecol);
  1151. var lookuprow = data.Rows.FirstOrDefault(r => Equals(r[field], tuple.Item1))
  1152. ?? data.NewRow(true);
  1153. foreach (CoreColumn lookupcol in data.Columns)
  1154. {
  1155. var columnname = String.IsNullOrWhiteSpace(prefix)
  1156. ? lookupcol.ColumnName
  1157. : String.Join(".", prefix, lookupcol.ColumnName);
  1158. var updatecol = Parent.Data.Columns.FirstOrDefault(x => String.Equals(x.ColumnName, columnname));
  1159. if (updatecol != null)
  1160. updates[updatecol] = lookuprow[lookupcol.ColumnName];
  1161. }
  1162. UpdateData(corecol, updates);
  1163. bChanged = true;
  1164. }
  1165. }
  1166. }
  1167. private void DataGrid_CurrentCellEndEdit(object? sender, CurrentCellEndEditEventArgs e)
  1168. {
  1169. if (_editingObject is not null && bChanged)
  1170. {
  1171. UpdateData(_editingObject.Row.Index, e.RowColumnIndex.ColumnIndex);
  1172. }
  1173. if (bChanged)
  1174. Parent.DoChanged();
  1175. bChanged = false;
  1176. _editingObject = null;
  1177. // Commented out on 19/02/2024 by Kenric. I don't see this being necessary, though I could be wrong. Nevertheless, it was causing a bug when
  1178. // editing the filter row. It seems that this causes Syncfusion to commit the filter predicates internally, which means that after leaving a
  1179. // filter row cell, the filter remained even once it was cleared, meaning a refresh was necessary to get the data back.
  1180. // I've tested on Bills to see if editing works with this empty, and it seems so.
  1181. //DataGridItems?.AcceptChanges();
  1182. }
  1183. private void DataGrid_PreviewKeyUp(object sender, KeyEventArgs e)
  1184. {
  1185. if (e.Key == Key.OemPeriod)
  1186. {
  1187. var editor = e.OriginalSource as TimeSpanEdit;
  1188. if (editor != null && editor.SelectionStart < 2) editor.SelectionStart = 3;
  1189. }
  1190. else if (e.Key == Key.Tab)
  1191. {
  1192. if (Parent.IsDirectEditMode())
  1193. {
  1194. DataGrid.SelectionController.CurrentCellManager.EndEdit();
  1195. DataGrid.MoveFocus(new TraversalRequest(FocusNavigationDirection.Right));
  1196. DataGrid.SelectionController.CurrentCellManager.BeginEdit();
  1197. e.Handled = true;
  1198. }
  1199. }
  1200. }
  1201. #endregion
  1202. #region Drag + Drop
  1203. private void DataGrid_DragOver(object sender, DragEventArgs e)
  1204. {
  1205. Parent.DragOver(sender, e);
  1206. }
  1207. private void DataGrid_Drop(object sender, DragEventArgs e)
  1208. {
  1209. Parent.Drop(sender, e);
  1210. }
  1211. private void RowDragDropController_DragStart(object? sender, GridRowDragStartEventArgs e)
  1212. {
  1213. var rows = e.DraggingRecords.Select(record =>
  1214. {
  1215. var rowIndex = DataGrid.ResolveToRowIndex(record);
  1216. return GetRowFromIndex(rowIndex);
  1217. }).NotNull().ToArray();
  1218. Parent.DragStart(sender, rows);
  1219. }
  1220. #endregion
  1221. }