DynamicGridGridUIComponent.cs 56 KB

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