DynamicGridGridUIComponent.cs 52 KB

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