| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895 | using InABox.Clients;using InABox.Core;using InABox.Scripting;using InABox.Wpf;using InABox.WPF;using Microsoft.Xaml.Behaviors;using org.omg.PortableInterceptor;using sun.reflect.generics.tree;using sun.util.resources.cldr.fr;using Syncfusion.Data;using Syncfusion.Data.Extensions;using Syncfusion.UI.Xaml.Grid;using Syncfusion.UI.Xaml.Grid.Cells;using Syncfusion.UI.Xaml.Grid.Helpers;using Syncfusion.UI.Xaml.ScrollAxis;using System;using System.Collections;using System.Collections.Generic;using System.Collections.ObjectModel;using System.ComponentModel;using System.Data;using System.Diagnostics.CodeAnalysis;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows;using System.Windows.Controls;using System.Windows.Controls.Primitives;using System.Windows.Data;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Effects;using System.Windows.Media.Imaging;using System.Windows.Threading;using DataColumn = System.Data.DataColumn;using DataRow = System.Data.DataRow;using TimeSpanEdit = Syncfusion.Windows.Shared.TimeSpanEdit;namespace InABox.DynamicGrid;public enum DynamicGridLines{    Both,    Horizontal,    Vertical,    None}public class DynamicGridGridUIComponent<T> : IDynamicGridUIComponent<T>, IDynamicGridGridUIComponent<T>    where T : BaseObject, new(){    private readonly Dictionary<string, string> _filterpredicates = new();        private Dictionary<string, CoreTable> Lookups = new();    private IDynamicGridUIComponentParent<T> _parent;    public IDynamicGridUIComponentParent<T> Parent    {        get => _parent;        set        {            _parent = value;            CellBackgroundConverter = new DynamicGridGridCellStyleConverter<System.Windows.Media.Brush?>(Parent, GetCellBackground);            CellForegroundConverter = new DynamicGridGridCellStyleConverter<System.Windows.Media.Brush?>(Parent, GetCellForeground);            CellFontSizeConverter = new DynamicGridGridCellStyleConverter<double?>(Parent, GetCellFontSize);            CellFontStyleConverter = new DynamicGridGridCellStyleConverter<System.Windows.FontStyle?>(Parent, GetCellFontStyle);            CellFontWeightConverter = new DynamicGridGridCellStyleConverter<System.Windows.FontWeight?>(Parent, GetCellFontWeight);            DataGrid.RowStyleSelector = Parent.RowStyleSelector;            DataGrid.TableSummaryRowStyleSelector = new SummaryRowStyleSelector(this, GetSummaryRowStyle);            DataGrid.TableSummaryCellStyleSelector = new SummaryCellStyleSelector(this, GetSummaryCellStyle);        }    }    FrameworkElement IDynamicGridUIComponent<T>.Control => DataGrid;    #region IDynamicGridGridUIComponent    IList<DynamicColumnBase> IDynamicGridGridUIComponent<T>.ColumnList => ColumnList;    int IDynamicGridGridUIComponent<T>.RowHeight => (int)RowHeight;    #endregion    protected readonly SfDataGrid DataGrid;    private readonly ContextMenu ColumnsMenu;    private readonly GridRowSizingOptions gridRowResizingOptions = new() { CanIncludeHiddenColumns = false, AutoFitMode = AutoFitMode.Default };    /// <summary>    /// <see langword="null"/> when <see cref="DataGrid.ItemsSource"/> is <see langword="null"/>, generally while the grid is refreshing its columns.    /// </summary>    private DataTable? DataGridItems => (DataGrid.ItemsSource as DataTable);    private DynamicGridGridCellStyleConverter<System.Windows.Media.Brush?> CellBackgroundConverter;    private DynamicGridGridCellStyleConverter<System.Windows.Media.Brush?> CellForegroundConverter;    private DynamicGridGridCellStyleConverter<double?> CellFontSizeConverter;    private DynamicGridGridCellStyleConverter<System.Windows.FontStyle?> CellFontStyleConverter;    private DynamicGridGridCellStyleConverter<System.Windows.FontWeight?> CellFontWeightConverter;    #region Configuration    private DynamicGridLines _gridLines = DynamicGridLines.Both;    public DynamicGridLines GridLines    {        get => _gridLines;        set        {            _gridLines = value;            DataGrid.GridLinesVisibility = value switch            {                DynamicGridLines.Both => GridLinesVisibility.Both,                DynamicGridLines.Vertical => GridLinesVisibility.Vertical,                DynamicGridLines.Horizontal => GridLinesVisibility.Horizontal,                _ => GridLinesVisibility.None,            };        }    }    public double RowHeight    {        get => DataGrid.RowHeight;        set => DataGrid.RowHeight = value;    }    public double HeaderRowHeight    {        get => DataGrid.HeaderRowHeight;        set => DataGrid.HeaderRowHeight = value;    }    #endregion    public DynamicGridGridUIComponent()    {        ColumnsMenu = new ContextMenu();        ColumnsMenu.Opened += ColumnsMenu_ContextMenuOpening;        DataGrid = new SfDataGrid();        DataGrid.VerticalAlignment = VerticalAlignment.Stretch;        DataGrid.HorizontalAlignment = HorizontalAlignment.Stretch;        DataGrid.HeaderContextMenu = ColumnsMenu;        DataGrid.CellTapped += DataGrid_CellTapped;        DataGrid.CellDoubleTapped += DataGrid_CellDoubleTapped;        DataGrid.SelectionChanging += DataGrid_SelectionChanging;        DataGrid.SelectionChanged += DataGrid_SelectionChanged;        DataGrid.SelectionMode = GridSelectionMode.Extended;        DataGrid.SelectionUnit = GridSelectionUnit.Row;        DataGrid.CanMaintainScrollPosition = true;        DataGrid.SummaryCalculationUnit = SummaryCalculationUnit.AllRows;        DataGrid.LiveDataUpdateMode = LiveDataUpdateMode.AllowSummaryUpdate;        DataGrid.NavigationMode = NavigationMode.Row;        DataGrid.AllowEditing = false;        DataGrid.EditTrigger = EditTrigger.OnTap;        DataGrid.CurrentCellBeginEdit += DataGrid_CurrentCellBeginEdit;        DataGrid.CurrentCellEndEdit += DataGrid_CurrentCellEndEdit;        DataGrid.CurrentCellDropDownSelectionChanged += DataGrid_CurrentCellDropDownSelectionChanged;        DataGrid.PreviewKeyUp += DataGrid_PreviewKeyUp;        DataGrid.BorderBrush = new SolidColorBrush(Colors.Gray);        DataGrid.BorderThickness = new Thickness(0.75F);        DataGrid.Background = new SolidColorBrush(Colors.DimGray);        DataGrid.AutoGenerateColumns = false;        DataGrid.ColumnSizer = GridLengthUnitType.AutoLastColumnFill;        DataGrid.SelectionForegroundBrush = GetCellSelectionForegroundBrush() ?? DynamicGridUtils.SelectionForeground;        DataGrid.RowSelectionBrush =  GetCellSelectionBackgroundBrush() ?? DynamicGridUtils.SelectionBackground;                DataGrid.AllowDraggingRows = false;        DataGrid.Drop += DataGrid_Drop;        DataGrid.DragOver += DataGrid_DragOver;        DataGrid.RowDragDropTemplate = TemplateGenerator.CreateDataTemplate(() =>        {            // var border = new Border();            // border.Width = 100;            // border.Height = 100;            // border.BorderBrush = new SolidColorBrush(Colors.Firebrick);            // border.Background = new SolidColorBrush(Colors.Red);            // border.CornerRadius = new CornerRadius(5);            // return border;            return null;        });        DataGrid.RowDropIndicatorMode = DropIndicatorMode.Line;        DataGrid.RowDragDropController ??= new GridRowDragDropController();                DataGrid.CurrentCellBorderThickness = new Thickness(0);        DataGrid.EnableDataVirtualization = true;        DataGrid.RowHeight = 30;        DataGrid.QueryRowHeight += DataGrid_QueryRowHeight;        DataGrid.HeaderRowHeight = 30;        DataGrid.MouseLeftButtonUp += DataGrid_MouseLeftButtonUp;        DataGrid.MouseRightButtonUp += DataGrid_MouseRightButtonUp;        DataGrid.KeyUp += DataGrid_KeyUp;        DataGrid.PreviewGotKeyboardFocus += DataGrid_PreviewGotKeyboardFocus;        DataGrid.SelectionController = new GridSelectionControllerExt(DataGrid, this);                DataGrid.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Visible);                DataGrid.FilterChanged += DataGrid_FilterChanged;        var fltstyle = new Style(typeof(GridFilterControl));        fltstyle.Setters.Add(new Setter(GridFilterControl.FilterModeProperty, FilterMode.Both));        fltstyle.Setters.Add(new Setter(GridFilterControl.SortOptionVisibilityProperty, Visibility.Collapsed));        DataGrid.FilterPopupStyle = fltstyle;        DataGrid.CellToolTipOpening += DataGrid_CellToolTipOpening;        DataGrid.SizeChanged += DataGrid_SizeChanged;    }    public class GridSelectionControllerExt(SfDataGrid datagrid, DynamicGridGridUIComponent<T> grid) : GridSelectionController(datagrid)    {        private DynamicGridGridUIComponent<T> Grid = grid;        public override bool HandleKeyDown(KeyEventArgs args)        {            if (args.Key == Key.Escape)            {                Grid.CancelEdit();                return false;            }            else            {                return base.HandleKeyDown(args);            }        }    }    private void ChangeValue(object oldValue, object newValue)    {    }    private void ColumnsMenu_ContextMenuOpening(object sender, RoutedEventArgs e)    {        if (sender is not ContextMenu menu) return;        menu.Items.Clear();        Parent.LoadColumnsMenu(menu);    }    #region Selection    public CoreRow[] SelectedRows    {        get => GetSelectedRows();        set => SetSelectedRows(value);    }    private CoreRow[] GetSelectedRows()    {        var result = new List<CoreRow>();        foreach (var item in DataGrid.SelectedItems)        {            if (item is DataRowView datarow && GetRow(datarow.Row) is CoreRow row)            {                result.Add(row);            }        }        return result.ToArray();    }    private void SetSelectedRows(CoreRow[] rows)    {                   DataGrid.SelectedItems.Clear();        var table = DataGridItems;        if(table is null) return;        var dataRows = rows.Select(x => _rowMap.FirstOrDefault(y => x == y.Value).Key);        if (!Parent.Options.MultiSelect)        {            dataRows = dataRows.Take(1);        }        foreach (var row in dataRows)        {            var record = DataGrid.View?.Records.FirstOrDefault(x => (x.Data as DataRowView)!.Row == row);            if(record?.Data is DataRowView rowView)            {                DataGrid.SelectedItems.Add(rowView);            }        }    }    private void DataGrid_SelectionChanging(object? sender, Syncfusion.UI.Xaml.Grid.GridSelectionChangingEventArgs e)    {        var cancel = new CancelEventArgs();        Parent.BeforeSelection(cancel);        if (cancel.Cancel)        {            e.Cancel = true;        }    }    private void DataGrid_SelectionChanged(object? sender, GridSelectionChangedEventArgs e)    {        if(Parent.IsReady && !Parent.IsRefreshing)        {            StartTimer();        }    }    private DispatcherTimer? clicktimer;    private void StartTimer()    {        if (clicktimer is null)        {            clicktimer = new DispatcherTimer();            clicktimer.Interval = TimeSpan.FromMilliseconds(200);            clicktimer.Tick += (o, e) =>            {                clicktimer.IsEnabled = false;                Parent.SelectItems(SelectedRows);            };        }        clicktimer.IsEnabled = true;    }    private void StopTimer()    {        if (clicktimer is not null)            clicktimer.IsEnabled = false;    }    #endregion    public CoreRow[] GetVisibleRows()    {        var items = DataGrid.ItemsSource;        var result = new List<CoreRow>();        var table = DataGridItems;        if (table is null) return Array.Empty<CoreRow>();        var rows = DataGrid.View.Records.Select(x => (x.Data as DataRowView)!).ToList();        foreach (var row in rows)        {            if(GetRow(row.Row) is CoreRow coreRow)            {                result.Add(coreRow);            }        }        return result.ToArray();    }    private bool bFilterVisible;    private void DataGrid_MouseRightButtonUp(object sender, MouseButtonEventArgs e)    {        if (!DataGrid.IsEnabled)            return;        var visualContainer = DataGrid.GetVisualContainer();        var rowcolumnindex = visualContainer.PointToCellRowColumnIndex(e.GetPosition(visualContainer));        var columnindex = DataGrid.ResolveToGridVisibleColumnIndex(rowcolumnindex.ColumnIndex);        var column = GetColumn(columnindex);        if(column is not null)        {            Parent.OpenColumnMenu(column);        }    }    private void DataGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)    {        if (!DataGrid.IsEnabled)            return;        var visualContainer = DataGrid.GetVisualContainer();        var rowcolumnindex = visualContainer.PointToCellRowColumnIndex(e.GetPosition(visualContainer));        var columnindex = DataGrid.ResolveToGridVisibleColumnIndex(rowcolumnindex.ColumnIndex);        // Header Click Here!        if (rowcolumnindex.RowIndex < DataGrid.StackedHeaderRows.Count + 1)        {            var column = GetColumn(columnindex);            if(column is DynamicActionColumn dac)            {                Parent.ExecuteActionColumn(dac, null);            }        }        else if (!bFilterVisible)        {            StartTimer();        }    }    private void DataGrid_CellTapped(object? sender, GridCellTappedEventArgs e)    {        if (!DataGrid.IsEnabled)            return;        if (GetColumn(e.RowColumnIndex.ColumnIndex) is DynamicActionColumn dac)        {            if(e.ChangedButton == MouseButton.Left || (e.ChangedButton == MouseButton.Right && dac is DynamicMenuColumn))            {                Parent.ExecuteActionColumn(dac, SelectedRows);            }        }        else        {            StartTimer();        }    }    private void DataGrid_KeyUp(object sender, KeyEventArgs e)    {        if (sender != DataGrid) return;        Parent.HandleKey(e);    }    private void DataGrid_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)    {        var bOld = bFilterVisible;        if (e.NewFocus is GridFilterControl)            bFilterVisible = true;        else if (e.NewFocus is ScrollViewer || e.NewFocus is SfDataGrid)            bFilterVisible = false;        if (bOld && !bFilterVisible)        {            Parent.SelectItems(SelectedRows);        }    }    // Please always use this function where possible!    /// <summary>    /// Get the <see cref="CoreRow"/> associated with a <paramref name="rowIndex"/> given from the Syncfusion DataGrid.    /// </summary>    /// <remarks>    /// This is mandatory to use whenever we want the data associated with an index which Syncfusion has given us,    /// because filtering and sorting will cause normal indexing operations to fail.    /// </remarks>    /// <param name="rowIndex"></param>    /// <returns></returns>    private CoreRow? GetRowFromIndex(int rowIndex)    {        // Syncfusion has given us the row index, so it also will give us the correct row, after sorting.        // Hence, here we use the syncfusion DataGrid.GetRecordAtRowIndex, which *should* always return a DataRowView.        var row = DataGrid.GetRecordAtRowIndex(rowIndex);        if (row is not DataRowView dataRowView || DataGridItems is not DataTable table)            return null;        return GetRow(dataRowView.Row);    }    private CoreRow? GetRow(DataRow row)    {        return _rowMap.GetValueOrDefault(row);    }    private void DataGrid_CellDoubleTapped(object? sender, GridCellDoubleTappedEventArgs e)    {        StopTimer();        Parent.DoubleClickCell(GetRowFromIndex(e.RowColumnIndex.RowIndex), GetColumn(e.RowColumnIndex.ColumnIndex));    }        private void DataGrid_QueryRowHeight(object? sender, QueryRowHeightEventArgs e)    {        if (e.RowIndex > 0)        {            e.Height = DataGrid.RowHeight;            if (DataGrid.GridColumnSizer.GetAutoRowHeight(e.RowIndex, gridRowResizingOptions, out var autoHeight))                if (autoHeight > DataGrid.RowHeight)                    e.Height = autoHeight;            e.Handled = true;        }    }    private void DataGrid_SizeChanged(object sender, SizeChangedEventArgs e)    {        if (Parent.IsReady && !Parent.IsRefreshing)            ResizeColumns(DataGrid, e.NewSize.Width - 2, e.NewSize.Height - 2);    }    public bool OptionsChanged()    {        ColumnsMenu.Visibility = Parent.Options.SelectColumns ? Visibility.Visible : Visibility.Hidden;        var allowEditing = Parent.IsDirectEditMode();        var reloadColumns = false;        if (DataGrid.AllowEditing != allowEditing)        {            DataGrid.NavigationMode = allowEditing ? NavigationMode.Cell : NavigationMode.Row;            DataGrid.AllowEditing = allowEditing;            reloadColumns = true;        }        DataGrid.FilterRowPosition = Parent.Options.FilterRows && Parent.CanFilter() ? FilterRowPosition.FixedTop : FilterRowPosition.None;        if (Parent.Options.DragSource || Parent.Options.ReorderRows)        {            if (!DataGrid.AllowDraggingRows)            {                DataGrid.AllowDraggingRows = true;                DataGrid.RowDragDropController.DragStart += RowDragDropController_DragStart;                DataGrid.RowDragDropController.DragOver += RowDragDropController_DragOver;            }        }        else        {            if (DataGrid.AllowDraggingRows)            {                DataGrid.AllowDraggingRows = false;                DataGrid.RowDragDropController.DragStart -= RowDragDropController_DragStart;                DataGrid.RowDragDropController.DragOver -= RowDragDropController_DragOver;            }        }        if (Parent.Options.DragTarget || Parent.Options.ReorderRows)        {            if (!DataGrid.AllowDrop)            {                DataGrid.AllowDrop = true;                DataGrid.RowDragDropController.Drop += RowDragDropController_Drop;                DataGrid.RowDragDropController.Dropped += RowDragDropController_Dropped;            }        }        else        {            if (DataGrid.AllowDrop)            {                DataGrid.AllowDrop = false;                DataGrid.RowDragDropController.Drop -= RowDragDropController_Drop;                DataGrid.RowDragDropController.Dropped -= RowDragDropController_Dropped;            }        }                DataGrid.SelectionMode = Parent.Options.MultiSelect ? GridSelectionMode.Extended : GridSelectionMode.Single;        return reloadColumns && DataGrid.Columns.Count > 0;    }    private void DataGrid_FilterChanged(object? o, GridFilterEventArgs e)    {        if (e.FilterPredicates == null)        {            if (_filterpredicates.ContainsKey(e.Column.MappingName))                _filterpredicates.Remove(e.Column.MappingName);        }        else        {            _filterpredicates[e.Column.MappingName] = Serialization.Serialize(e.FilterPredicates, true);        }        Parent.UIFilterChanged(this);        UpdateRecordCount();    }    private void UpdateRecordCount()    {        var count = DataGrid.View != null ? DataGrid.View.Records.Count : Parent.Data.Rows.Count;        Parent.UpdateRecordCount(count);    }    private void DataGrid_CellToolTipOpening(object? sender, GridCellToolTipOpeningEventArgs e)    {        var column = GetColumn(e.RowColumnIndex.ColumnIndex);        if (column is DynamicActionColumn ac)        {            var toolTip = ac.ToolTip;            if (toolTip is null)                return;            var row = GetRowFromIndex(e.RowColumnIndex.RowIndex);            e.ToolTip.Template = TemplateGenerator.CreateControlTemplate(                typeof(ToolTip),                () => toolTip.Invoke(ac, row)            );        }        else if(column is DynamicGridColumn gc)        {            e.ToolTip.Content = gc.Editor.ToolTip;        }    }    public void AddVisualFilter(string column, string value, FilterType filtertype = FilterType.Contains)    {        if (string.IsNullOrWhiteSpace(value))            return;        var col = DataGrid.Columns.FirstOrDefault((x=>String.Equals(x.MappingName?.ToUpper(),column?.Replace(".", "_").ToUpper())));        if (col != null)        {            col.FilterPredicates.Add(new FilterPredicate { FilterType = filtertype, FilterValue = value });            col.FilteredFrom = FilteredFrom.FilterRow;        }    }    public List<Tuple<string, Func<CoreRow, bool>>> GetFilterPredicates()    {        var list = new List<Tuple<string, Func<CoreRow, bool>>>();        foreach (var column in DataGrid.Columns)        {            var colIndex = DataGrid.Columns.IndexOf(column);            var col = ColumnList[colIndex];            var filter = Parent.GetColumnFilter(col);            if (col is DynamicGridColumn gridColumn)            {                var rowPredicate = DynamicGridGridUIComponentExtension.ConvertColumnPredicates(gridColumn, column.FilterPredicates);                if(filter is not null)                {                    var oldPred = rowPredicate;                    if(oldPred is not null)                    {                        rowPredicate = row => oldPred(row) && filter.FilterRow(row);                    }                    else                    {                        rowPredicate = filter.FilterRow;                    }                }                if(rowPredicate is not null)                {                    list.Add(new(gridColumn.ColumnName, rowPredicate));                }            }            else if(col is DynamicActionColumn dac)            {                if(filter is not null)                {                    list.Add(new(column.MappingName, filter.FilterRow));                }            }        }        return list;    }    public void ScrollIntoView(CoreRow row)    {        var rowIdx = DataGrid.ResolveToRowIndex(row.Index + 1);        DataGrid.ScrollInView(new RowColumnIndex(rowIdx, 0));    }    #region Styles    protected virtual Brush? GetCellSelectionForegroundBrush() => DynamicGridUtils.SelectionForeground;    protected virtual Brush? GetCellSelectionBackgroundBrush() => DynamicGridUtils.SelectionBackground;    protected virtual Brush? GetCellBackground(CoreRow row, DynamicColumnBase column) => null;    protected virtual Brush? GetCellForeground(CoreRow row, DynamicColumnBase column) => null;    protected virtual double? GetCellFontSize(CoreRow row, DynamicColumnBase column) => null;    protected virtual FontStyle? GetCellFontStyle(CoreRow row, DynamicColumnBase column) => null;    protected virtual FontWeight? GetCellFontWeight(CoreRow row, DynamicColumnBase column) => null;    protected virtual Style GetCellStyle(DynamicColumnBase column)    {        var style = new Style(typeof(GridCell));        return style;    }    protected virtual Style GetHeaderCellStyle(DynamicColumnBase column)    {        var headStyle = new Style(typeof(GridHeaderCellControl));        headStyle.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));        headStyle.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));        headStyle.Setters.Add(new Setter(Control.FontSizeProperty, 12D));        if (column is DynamicActionColumn actionColumn)        {            headStyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0.0)));            headStyle.Setters.Add(new Setter(Control.MarginProperty, new Thickness(0, 0, 1, 1)));            if (column is DynamicImageColumn imgCol)            {                if (imgCol.HeaderText.IsNullOrWhiteSpace())                {                    var image = imgCol.Image?.Invoke(null);                    if (image != null)                    {                        headStyle.AddSetter(GridHeaderCellControl.PaddingProperty, new Thickness(4.0));                        headStyle.AddSetter(GridHeaderCellControl.ContentTemplateProperty,                            TemplateGenerator.CreateDataTemplate(() =>                            {                                return new Image { Source = image };                            }));                    }                }            }            if (actionColumn.VerticalHeader && !actionColumn.HeaderText.IsNullOrWhiteSpace())            {                headStyle.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Left));                headStyle.Setters.Add(new Setter(Control.TemplateProperty,                    Application.Current.Resources["VerticalColumnHeader"] as ControlTemplate));            }        }        return headStyle;    }    protected virtual Style GetColumnGroupHeaderCellStyle(DynamicGridColumnGroup group)    {        var headstyle = new Style(typeof(GridStackedHeaderCellControl));        headstyle.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));        headstyle.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));        headstyle.Setters.Add(new Setter(Control.FontSizeProperty, 12D));        headstyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0.0, 0.0, 0, 0)));        headstyle.Setters.Add(new Setter(Control.MarginProperty, new Thickness(0, 0, 1, 1)));        return headstyle;    }    protected virtual Style GetSummaryRowStyle()    {        var style = new Style(typeof(TableSummaryRowControl));        return style;    }    protected virtual Style GetSummaryCellStyle(DynamicColumnBase column)    {        var style = new Style(typeof(GridTableSummaryCell));        style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));        style.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));        if(column is DynamicGridColumn gridColumn)        {            style.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty,                column != null ? gridColumn.HorizontalAlignment(typeof(double)) : HorizontalAlignment.Right));        }        else if(column is DynamicTextColumn textColumn)        {            style.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, textColumn.Alignment.HorizontalAlignment(typeof(string))));        }        else        {            style.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Right));        }        style.Setters.Add(new Setter(Control.BorderBrushProperty, new SolidColorBrush(Colors.Gray)));        style.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0, 0, 0.75, 0)));        style.Setters.Add(new Setter(Control.FontSizeProperty, 12D));        style.Setters.Add(new Setter(Control.FontWeightProperty, FontWeights.DemiBold));        return style;    }    #endregion    #region Columns    private readonly List<DynamicColumnBase> ColumnList = new();    private List<DynamicActionColumn> ActionColumns = new();    private DynamicColumnBase? GetColumn(int index) =>        index >= 0 && index < ColumnList.Count ? ColumnList[index] : null;    private class StackedHeaderRenderer : GridStackedHeaderCellRenderer    {        private DynamicGridGridUIComponent<T> Grid;        public StackedHeaderRenderer(DynamicGridGridUIComponent<T> grid)        {            Grid = grid;        }        public override void OnInitializeEditElement(DataColumnBase dataColumn, GridStackedHeaderCellControl uiElement, object dataContext)        {            if(dataContext is StackedColumn column && Grid.ColumnGroupMap.TryGetValue(column.MappingName, out var group))            {                uiElement.Style = Grid.GetColumnGroupHeaderCellStyle(group);            }            base.OnInitializeEditElement(dataColumn, uiElement, dataContext);        }    }    private Dictionary<string, DynamicGridColumnGroup> ColumnGroupMap = new();    private void LoadStackedHeaders(DynamicGridColumnGroupings groupings)    {        DataGrid.StackedHeaderRows.Clear();        ColumnGroupMap.Clear();        var j = 0;        foreach(var grouping in groupings)        {            var row = new StackedHeaderRow();            var i = 0;            foreach(var group in grouping.Groups)            {                var start = Math.Max(i, ColumnList.IndexOf(group.StartColumn));                var end = Math.Max(start, ColumnList.IndexOf(group.EndColumn));                if(end < start)                {                    i = end + 1;                    continue;                }                var cols = Enumerable.Range(start, end - start + 1).Select(i => DataGrid.Columns[i]).ToArray();                var name = $"_GroupColumn{j}";                var stackedColumn = new StackedColumn                {                    HeaderText = group.Header,                    ChildColumns = string.Join(',', cols.Select(x => x.MappingName)),                    MappingName = name                };                ColumnGroupMap.Add(name, group);                j = j + 1;                row.StackedColumns.Add(stackedColumn);                i = end + 1;            }            DataGrid.StackedHeaderRows.Add(row);        }        if(groupings.Count > 0)        {            DataGrid.CellRenderers.Remove("StackedHeader");            DataGrid.CellRenderers.Add("StackedHeader", new StackedHeaderRenderer(this));        }    }    int IDynamicGridUIComponent<T>.DesiredWidth()    {        return this.DesiredWidth();    }    private void ResizeColumns(SfDataGrid grid, double width, double height)    {        if (Parent.Data == null || width <= 0)            return;        grid.Dispatcher.BeginInvoke(() =>        {            foreach (var (index, size) in this.CalculateColumnSizes(width))                DataGrid.Columns[index].Width = Math.Max(0.0F, size);        });    }    private ObservableCollection<ISummaryColumn> Summaries = new();    private void AddCellStyleConverters(Style cellstyle, DynamicColumnBase column, string sColName)    {        cellstyle.Setters.Add(new Setter(Control.BackgroundProperty,            WPFUtils.CreateMultiBinding(                CellBackgroundConverter.WrapConverter(x => x[0]),                parameter: new DynamicGridCellStyleParameters(column, DependencyProperty.UnsetValue))                .AddBinding(new Binding("."))                .AddBinding(new Binding(sColName))));        cellstyle.Setters.Add(new Setter(Control.ForegroundProperty,            WPFUtils.CreateMultiBinding(                CellForegroundConverter.WrapConverter(x => x[0]),                parameter: new DynamicGridCellStyleParameters(column, DependencyProperty.UnsetValue))                .AddBinding(new Binding("."))                .AddBinding(new Binding(sColName))));        cellstyle.Setters.Add(new Setter(Control.FontSizeProperty,            WPFUtils.CreateMultiBinding(                CellFontSizeConverter.WrapConverter(x => x[0]),                parameter: new DynamicGridCellStyleParameters(column, DependencyProperty.UnsetValue))                .AddBinding(new Binding("."))                .AddBinding(new Binding(sColName))));        cellstyle.Setters.Add(new Setter(Control.FontStyleProperty,            WPFUtils.CreateMultiBinding(                CellFontStyleConverter.WrapConverter(x => x[0]),                parameter: new DynamicGridCellStyleParameters(column, DependencyProperty.UnsetValue))                .AddBinding(new Binding("."))                .AddBinding(new Binding(sColName))));        cellstyle.Setters.Add(new Setter(Control.FontWeightProperty,            WPFUtils.CreateMultiBinding(                CellFontWeightConverter.WrapConverter(x => x[0]),                parameter: new DynamicGridCellStyleParameters(column, DependencyProperty.UnsetValue))                .AddBinding(new Binding("."))                .AddBinding(new Binding(sColName))));    }    #region Column Filtering    private void ApplyFilterStyle(GridColumn column, bool filtering, bool allowSorting)    {        var filterstyle = new Style();        if (filtering)        {            filterstyle.Setters.Add(new Setter(Control.BackgroundProperty, DynamicGridUtils.FilterBackground));            column.ImmediateUpdateColumnFilter = true;            column.ColumnFilter = ColumnFilter.Value;            column.FilterRowCondition = FilterRowCondition.Contains;            column.FilterRowOptionsVisibility = Visibility.Collapsed;            column.AllowBlankFilters = true;            column.AllowSorting = allowSorting && Parent.CanSort();        }        else        {            filterstyle.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));            filterstyle.Setters.Add(new Setter(Control.IsEnabledProperty, false));            column.ColumnFilter = ColumnFilter.Value;            column.AllowSorting = false;            column.FilterRowEditorType = "TextBox";            column.FilterRowOptionsVisibility = Visibility.Collapsed;        }        column.FilterRowCellStyle = filterstyle;    }    private void Filter_FilterChanged(IDynamicGridColumnFilter filter)    {        AddRows(Parent.Data.Rows, true);        Parent.UIFilterChanged(this);    }    private bool FilterRow(CoreRow row)    {        foreach(var column in ColumnList)        {            if(Parent.GetColumnFilter(column) is IDynamicGridColumnFilter filter && !filter.FilterRow(row))            {                return false;            }        }        return true;    }    private void SetFilterUIButton(GridColumn gridColumn, DynamicColumnBase column)    {        if (!Parent.Options.FilterRows || !Parent.CanFilter()) return;        if (Parent.GetColumnFilter(column) is not IDynamicGridColumnFilter filter) return;        var vertical = column is DynamicActionColumn ac && ac.VerticalHeader && !ac.HeaderText.IsNullOrWhiteSpace();        var horizontalAlignment = gridColumn.HorizontalHeaderContentAlignment;        gridColumn.HorizontalHeaderContentAlignment = HorizontalAlignment.Stretch;        gridColumn.HeaderTemplate = TemplateGenerator.CreateDataTemplate(() =>        {            var grid = new Grid();            grid.AddColumn(GridUnitType.Star);            var filterCol = grid.AddColumn(GridUnitType.Auto);            var content = new ContentControl();            content.HorizontalAlignment = horizontalAlignment;            content.VerticalAlignment = VerticalAlignment.Center;            content.SetBinding(ContentControl.ContentProperty, new Binding());            grid.AddChild(content, 0, 0);            var button = new DynamicGridColumnFilterUIButton(filter);            grid.AddChild(button, 0, 1);            if(vertical)            {                button.LayoutTransform = new RotateTransform(90);                content.HorizontalAlignment = HorizontalAlignment.Stretch;            }            return grid;        });    }    #endregion    #region Summaries    public class SummaryRowStyleSelector(DynamicGridGridUIComponent<T> parent, Func<Style> selector) : StyleSelector    {        public DynamicGridGridUIComponent<T> Parent { get; init; } = parent;        public Func<Style> Selector { get; set; } = selector;        public override Style? SelectStyle(object item, DependencyObject container)        {            return Selector();        }    }    public class SummaryCellStyleSelector(DynamicGridGridUIComponent<T> parent, Func<DynamicColumnBase, Style> selector) : StyleSelector    {        public DynamicGridGridUIComponent<T> Parent { get; init; } = parent;        public Func<DynamicColumnBase, Style> Selector { get; set; } = selector;        public override Style? SelectStyle(object item, DependencyObject container)        {            var vcol = ((GridTableSummaryCell)container).ColumnBase.ColumnIndex;            var col = Parent.GetColumn(vcol);            return col is not null ? Selector(col) : null;        }    }    private GridSummaryColumn? ConvertSummary(IDynamicGridSummary? summary)    {        if(summary is DynamicGridSumSummary sum)        {            var newSummary = new GridSummaryColumn            {                Format = $"{{Sum:{sum.Format}}}"            };            if(sum.AggregateType == typeof(double))            {                newSummary.SummaryType = Syncfusion.Data.SummaryType.DoubleAggregate;            }            else if(sum.AggregateType == typeof(int))            {                newSummary.SummaryType = Syncfusion.Data.SummaryType.Int32Aggregate;            }            else if(sum.AggregateType == typeof(TimeSpan))            {                newSummary.SummaryType = Syncfusion.Data.SummaryType.Custom;                newSummary.CustomAggregate = new DynamicGridDurationAggregate();            }            return newSummary;        }        else if(summary is DynamicGridCountSummary count)        {            return new GridSummaryColumn            {                Format = "{Count:N0}",                SummaryType = Syncfusion.Data.SummaryType.CountAggregate            };        }        else if(summary is DynamicGridCustomSummary custom)        {            return new GridSummaryColumn            {                Format = $"{{Sum:{custom.Format}}}",                SummaryType = SummaryType.Custom,                CustomAggregate = new InternalAggregate(this, custom.Aggregate)            };        }        else if(summary is DynamicGridTemplateSummary template)        {            return new GridSummaryColumn            {                TemplateSelector = new FuncTemplateSelector((item, o) => template.Template())            };        }        else        {            return null;        }    }    private class InternalAggregate(DynamicGridGridUIComponent<T> grid, DynamicGridCustomSummary.AggregateFunc aggregate) : ISummaryAggregate    {        private DynamicGridCustomSummary.AggregateFunc Aggregate = aggregate;        private DynamicGridGridUIComponent<T> Grid = grid;        public object? Sum { get; set; } = null;        public Action<IEnumerable, string, PropertyDescriptor> CalculateAggregateFunc() => CalculateAggregate;        private void CalculateAggregate(IEnumerable items, string property, PropertyDescriptor args)        {            if (items is IEnumerable<DataRowView> rows)            {                Sum = Aggregate(rows.Select(x =>                {                    return Grid.GetRow(x.Row);                }).NotNull());            }            else            {                Logger.Send(LogType.Error, "", $"Attempting to calculate aggregate on invalid data type '{items.GetType()}'.");            }        }    }    #endregion    private void LoadActionColumn(DynamicActionColumn column)    {        var i = ActionColumns.Count;        var sColName = string.Format("ActionColumn{0}", i);        ActionColumns.Add(column);        gridRowResizingOptions.ExcludeColumns.Add(sColName);        var summary = ConvertSummary(column.Summary());        if (summary != null)        {            summary.Name = sColName;            summary.MappingName = sColName;            Summaries.Add(summary);        }        if (column is DynamicImageColumn imgcol)        {            var newcol = new GridImageColumn();            newcol.MappingName = sColName;            newcol.Width = column.Width == 0 ? DataGrid.RowHeight : column.Width;            newcol.Padding = new Thickness(4);            newcol.ImageHeight = DataGrid.RowHeight - 8;            newcol.ImageWidth = DataGrid.RowHeight - 8;            newcol.ColumnSizer = GridLengthUnitType.None;            newcol.HeaderText = column.HeaderText;            newcol.AllowEditing = false;            ApplyFilterStyle(newcol, true, false);            SetFilterUIButton(newcol, column);            newcol.ShowToolTip = column.ToolTip != null;            newcol.ShowHeaderToolTip = column.ToolTip != null;            var style = new Style();            style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));            style.Setters.Add(new Setter(Control.IsEnabledProperty, false));            newcol.FilterRowCellStyle = style;            newcol.HeaderStyle = GetHeaderCellStyle(column);            var cellstyle = GetCellStyle(column);            AddCellStyleConverters(cellstyle, column, sColName);            newcol.CellStyle = cellstyle;            DataGrid.Columns.Add(newcol);            ColumnList.Add(column);        }        else if (column is DynamicTextColumn txtCol)        {            var newcol = new GridTextColumn();            gridRowResizingOptions.ExcludeColumns.Add(sColName);            newcol.TextWrapping = TextWrapping.NoWrap;            newcol.TextAlignment = txtCol.Alignment.TextAlignment(typeof(string));            newcol.AllowEditing = false;            newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged;            newcol.MappingName = sColName;            newcol.Width = column.Width;            newcol.ColumnSizer = GridLengthUnitType.None;            newcol.HeaderText = column.HeaderText;            newcol.AllowSorting = false;            newcol.FilterRowOptionsVisibility = Visibility.Collapsed;            newcol.ShowHeaderToolTip = column.ToolTip != null;                        newcol.ShowToolTip = column.ToolTip != null;            newcol.ShowHeaderToolTip = column.ToolTip != null;            ApplyFilterStyle(newcol, true, true);            SetFilterUIButton(newcol, column);            newcol.HeaderStyle = GetHeaderCellStyle(column);            var cellstyle = GetCellStyle(column);            AddCellStyleConverters(cellstyle, column, sColName);            newcol.CellStyle = cellstyle;            DataGrid.Columns.Add(newcol);            ColumnList.Add(column);        }        else if (column is DynamicTemplateColumn tmplCol)        {            var newcol = new GridTemplateColumn();            newcol.CellTemplate = TemplateGenerator.CreateDataTemplate(() =>            {                var content = new ContentControl();                content.SetBinding(ContentControl.ContentProperty,                    WPFUtils.CreateMultiBinding(new MultiFuncConverter(x =>                    {                        if(x[0] is DataRowView view && DataGridItems is DataTable table && GetRow(view.Row) is CoreRow row)                        {                            return tmplCol.Template(row);                        }                        return null;                    }))                        .AddBinding(new Binding("."))                        .AddBinding(new Binding(sColName)));                return content;            });            newcol.AllowEditing = false;            newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged;            newcol.MappingName = sColName;                        newcol.Width = tmplCol.Width;            newcol.ColumnSizer = GridLengthUnitType.None;            newcol.HeaderText = column.HeaderText;            newcol.AllowSorting = false;            newcol.FilterRowOptionsVisibility = Visibility.Collapsed;                        newcol.ShowToolTip = column.ToolTip != null;            newcol.ShowHeaderToolTip = column.ToolTip != null;            SetFilterUIButton(newcol, column);            var style = new Style();            style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));            style.Setters.Add(new Setter(Control.IsEnabledProperty, false));            newcol.FilterRowCellStyle = style;            newcol.HeaderStyle = GetHeaderCellStyle(column);            var cellstyle = GetCellStyle(column);            AddCellStyleConverters(cellstyle, column, sColName);            newcol.CellStyle = cellstyle;            DataGrid.Columns.Add(newcol);            ColumnList.Add(column);        }    }    private void LoadDataColumn(DynamicGridColumn column)    {        if (this.CreateEditorColumn(column, out var newcol, out var prop))        {            newcol.GetEntity = () => _editingObject?.Object;            newcol.EntityChanged += DoEntityChanged;            if (!newcol.VariableHeight)                gridRowResizingOptions.ExcludeColumns.Add(newcol.MappingName);            var newColumn = newcol.CreateGridColumn();            var summary = ConvertSummary(newcol.Summary());            if (summary != null)            {                summary.Name = newcol.MappingName;                summary.MappingName = newcol.MappingName;                Summaries.Add(summary);            }                        ApplyFilterStyle(newColumn, newcol.Filtered, true);                        newColumn.HeaderStyle = GetHeaderCellStyle(column);            SetFilterUIButton(newColumn, column);            newColumn.ShowHeaderToolTip = !column.Editor.ToolTip.IsNullOrWhiteSpace();            var cellstyle = GetCellStyle(column);            if (Parent.IsDirectEditMode())            {                var editor = Parent.CustomiseEditor(column, column.Editor);                if (editor is null || !newcol.Editable || !editor.Editable.IsDirectEditable())                {                    cellstyle.Setters.Add(new Setter(Control.BackgroundProperty,                        new Binding()                        {                            Path = new PropertyPath("."), Converter = CellBackgroundConverter,                            ConverterParameter = new DynamicGridCellStyleParameters(column,new SolidColorBrush(Colors.WhiteSmoke))                        }));                    newColumn.AllowEditing = false;                }                else                {                    cellstyle.Setters.Add(new Setter(Control.BackgroundProperty,                        new Binding()                        {                            Path = new PropertyPath("."), Converter = CellBackgroundConverter,                            ConverterParameter = new DynamicGridCellStyleParameters(column,new SolidColorBrush(Colors.LightYellow))                        }));                    newColumn.AllowEditing = true;                }                cellstyle.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));                newColumn.CellStyle = cellstyle;            }            else            {                AddCellStyleConverters(cellstyle, column, newColumn.MappingName);                newColumn.CellStyle = cellstyle;            }                        DataGrid.Columns.Add(newColumn);            ColumnList.Add(column);            foreach (var extra in newcol.ExtraColumns)                Parent.AddHiddenColumn(extra);        }    }    private void LoadSummaries()    {        if (Summaries.Any())        {            DataGrid.CellRenderers.Remove("TableSummary");            DataGrid.CellRenderers.Add("TableSummary", new DynamicGridAggregateRenderer());            DataGrid.TableSummaryRows.Add(new GridTableSummaryRow            {                ShowSummaryInRow = false,                Position = TableSummaryRowPosition.Bottom,                SummaryColumns = Summaries,            });        }    }    public void RefreshColumns(IEnumerable<DynamicColumnBase> columns, DynamicGridColumnGroupings groupings)    {        if (DataGrid.View != null)            DataGrid.View.Filter = null;                DataGrid.ItemsSource = null;        DataGrid.Columns.Suspend();        ColumnList.Clear();        ActionColumns.Clear();        DataGrid.Columns.Clear();        DataGrid.TableSummaryRows.Clear();        gridRowResizingOptions.ExcludeColumns = new List<string>();        Summaries.Clear();        foreach(var column in columns)        {            if(Parent.GetColumnFilter(column) is IDynamicGridColumnFilter filter)            {                filter.FilterChanged += Filter_FilterChanged;            }            if(column is DynamicActionColumn ac)            {                LoadActionColumn(ac);            }            else if(column is DynamicGridColumn gc)            {                LoadDataColumn(gc);            }        }        LoadSummaries();        LoadStackedHeaders(groupings);        DataGrid.Columns.Resume();        DataGrid.RefreshColumns();        foreach (var key in _filterpredicates.Keys.ToArray())            if (DataGrid.Columns.Any(x => string.Equals(x.MappingName, key)))            {                var predicates = Serialization.Deserialize<List<FilterPredicate>>(_filterpredicates[key]);                foreach (var predicate in predicates)                {                    DataGrid.Columns[key].FilterPredicates.Add(predicate);                    DataGrid.Columns[key].FilteredFrom = FilteredFrom.FilterRow;                }            }            else            {                _filterpredicates.Remove(key);            }        ResizeColumns(DataGrid, DataGrid.ActualWidth - 2, DataGrid.ActualHeight - 2);        if(groupings.Count > 0)        {            // THis here is to fix a problem with Syncfusion when we have stackedHeaderRows; the above setting of the ItemsSource to null            // was causing the resetting of it to fail when reloading, due to some internal OutOfRange Exception. THe use case was selecting columns on the            // Stock Forecast grid.            RefreshData(new CoreTable());        }        if (DataGrid.View != null)            DataGrid.View.Filter = (o) =>            {                return true;            };    }    #endregion    #region Data    private bool _invalidating = false;    private Dictionary<DataRow, CoreRow> _rowMap = new();    public void BeforeRefresh()    {        DataGrid.SelectionForegroundBrush = GetCellSelectionForegroundBrush();        DataGrid.RowSelectionBrush = GetCellSelectionBackgroundBrush();    }    public void RefreshData(CoreTable data)    {        var result = new DataTable();        _rowMap.Clear();        var defaults = new List<object?>();        foreach (var column in data.Columns)        {            var colname = column.ColumnName.Replace('.', '_');            if (!result.Columns.Contains(colname))            {                result.Columns.Add(colname, column.DataType);                if (!Parent.IsDirectEditMode())                    defaults.Add(column.DataType.GetDefault());            }        }        for (var i = 0; i < ActionColumns.Count; i++)            result.Columns.Add(string.Format("ActionColumn{0}", i),                ActionColumns[i] is DynamicImageColumn                    ? typeof(ImageSource)                    : typeof(String)            );        foreach (var row in data.Rows.Where(FilterRow))        {            var newrow = result.NewRow();            CoreRowToDataRow(newrow, row, defaults);            result.Rows.Add(newrow);            _rowMap[newrow] = row;        }        result.ColumnChanged += Result_ColumnChanged;        //int rowIndex = DataGrid.SelectionController.CurrentCellManager.CurrentRowColumnIndex.RowIndex;        //int columnIndex = DataGrid.SelectionController.CurrentCellManager.CurrentRowColumnIndex.ColumnIndex;        //int scrollRowIndex = DataGrid.GetVisualContainer().ScrollRows.LastBodyVisibleLineIndex;        //this.DataGrid.ScrollInView(new Syncfusion.UI.Xaml.ScrollAxis.RowColumnIndex(scrollRowIndex, columnIndex));        DataGrid.ItemsSource = result;        ResizeColumns(DataGrid, DataGrid.ActualWidth - 1, DataGrid.ActualHeight);        UpdateRecordCount();    }    private void AddRows(IEnumerable<CoreRow> rows, bool clearRows)    {        var table = DataGridItems;        if(table is null)        {            return;        }        _invalidating = true;        if (clearRows)        {            table.Rows.Clear();            _rowMap.Clear();        }        var defaults = new List<object?>();        if (!Parent.IsDirectEditMode())            foreach (var column in table.Columns.Cast<DataColumn>())            {                defaults.Add(column.DataType.GetDefault());            }        foreach(var row in rows.Where(FilterRow))        {            var newRow = table.NewRow();            CoreRowToDataRow(newRow, row, defaults);            table.Rows.Add(newRow);            _rowMap[newRow] = row;        }        UpdateRecordCount();        _invalidating = false;    }    public void AddPage(IEnumerable<CoreRow> page)    {        AddRows(page, false);    }    public void InvalidateRow(CoreRow row)    {        var table = DataGridItems;        if(table is null)        {            return;        }        _invalidating = true;        var rowdata = new List<object?>(row.Values);        foreach (var ac in ActionColumns)            rowdata.Add(ac.Data(row));        //DataGridItems.Rows.RemoveAt(row.Index);        //var datarow = DataGridItems.NewRow();        var datarow = DataGridItems.Rows[row.Index];        for (var i = 0; i < rowdata.Count; i++)            datarow[i] = rowdata[i] ?? DBNull.Value;        //DataGridItems.Rows.InsertAt(datarow, row.Index);        _invalidating = false;    }    private void CoreRowToDataRow(DataRow newrow, CoreRow row, List<object?> defaults)    {        var rowdata = new List<object?>(row.Values);        foreach (var ac in ActionColumns)            rowdata.Add(ac.Data(row));        try        {            var data = ProcessRow(rowdata, defaults).ToArray();            newrow.ItemArray = data;        }        catch (Exception)        {            throw;        }    }    private static IEnumerable<object?> ProcessRow(List<object?> values, List<object?> defaults)    {        if (defaults == null || defaults.Count == 0)            return values;        var result = new List<object?>();        for (var i = 0; i < values.Count; i++)        {            var value = values[i];            var defaultvalue = i < defaults.Count ? defaults[i] : null;            result.Add(value == null || (value.Equals(defaultvalue) && !value.GetType().IsEnum) ? null : value);        }        return result;    }    #endregion    #region Direct Edit    private bool bChanged;    private class DirectEditingObject    {        public T Object { get; set; }        public CoreRow Row { get; set; }        public DataRow? DataRow { get; set; }        public DirectEditingObject(T obj, CoreRow row, DataRow? dataRow)        {            Object = obj;            Row = row;            DataRow = dataRow;        }    }    private DirectEditingObject? _editingObject;    private DirectEditingObject EnsureEditingObject(CoreRow row)    {        _editingObject ??= new(Parent.LoadItem(row), row, DataGridItems?.Rows[row.Index]);        return _editingObject;    }    private DataRow? GetDataRow(CoreRow row)    {        return DataGridItems?.Rows[row.Index];    }    void IDynamicGridUIComponent<T>.UpdateCell(CoreRow row, string column, object? value)    {        var dataRow = GetDataRow(row);        var datacolname = column.Replace(".", "_");        if(dataRow is not null)        {            dataRow[datacolname] = value ?? DBNull.Value;        }    }    void IDynamicGridUIComponent<T>.UpdateCell(CoreRow row, DynamicColumnBase column)    {        var dataRow = GetDataRow(row);        if(dataRow is not null)        {            if(column is DynamicGridColumn gc)            {                var dataColName = gc.ColumnName.Replace(".", "_");                dataRow[dataColName] = row[gc.ColumnName] ?? DBNull.Value;            }            else if(column is DynamicActionColumn ac)            {                var i = ActionColumns.IndexOf(ac);                dataRow[$"ActionColumn{i}"] = ac.Data(row);            }        }    }    void UpdateRow(CoreRow row, DataRow dataRow)    {        foreach(var (key, value) in row)        {            var datacolname = key.Replace(".", "_");            var dataValue = dataRow[datacolname];            if (!Equals(dataValue, value) && !(value is null && dataValue == DBNull.Value))            {                dataRow[datacolname] = value ?? DBNull.Value;            }        }        for (var i = 0; i < ActionColumns.Count; i++)            dataRow[$"ActionColumn{i}"] = ActionColumns[i].Data(row);    }    void IDynamicGridUIComponent<T>.UpdateRow(CoreRow row)    {        var dataRow = GetDataRow(row);        if(dataRow is not null)        {            UpdateRow(row, dataRow);        }    }    private void DoEntityChanged(IDynamicColumnBase column, DynamicColumnEntityChangedEventArgs args)    {        if (_editingObject is null) return;        Parent.EntityChanged(_editingObject.Object, _editingObject.Row, args.ColumnName, args.Changes);    }    private void UpdateData(string column, Dictionary<CoreColumn, object?> updates)    {        if (_editingObject is null)            return;        var coreRow = _editingObject.Row;        Parent.UpdateData(_editingObject.Object, coreRow, column, updates);    }    private void UpdateData(int rowIndex, int columnIndex)    {        var table = DataGridItems;        if (table is null)            return;                if (GetColumn(columnIndex) is DynamicGridColumn gridcol)        {            var datacol = Parent.Data.Columns.FirstOrDefault(x => x.ColumnName.Equals(gridcol.ColumnName));            if (datacol != null)            {                var datacolindex = Parent.Data.Columns.IndexOf(datacol);                var value = table.Rows[rowIndex][datacolindex];                if (value is DBNull)                    value = CoreUtils.GetDefault(datacol.DataType);                UpdateData(datacol.ColumnName, new Dictionary<CoreColumn, object?>() { { datacol, value } });            }        }    }    private void DataGrid_CurrentCellBeginEdit(object? sender, CurrentCellBeginEditEventArgs e)    {        var table = DataGridItems;        var row = GetRowFromIndex(e.RowColumnIndex.RowIndex);        if (table is null || row is null)            return;        EnsureEditingObject(row);        var column = DataGrid.Columns[e.RowColumnIndex.ColumnIndex] as GridComboBoxColumn;        if (column != null && column.ItemsSource == null)        {            var colname = column.MappingName;            var colno = table.Columns.IndexOf(colname);            var property = Parent.Data.Columns[colno].ColumnName;            var prop = CoreUtils.GetProperty(typeof(T), property);            var editor = prop.GetEditor();            if (editor is ILookupEditor lookupEditor)            {                if (!Lookups.ContainsKey(property))                    Lookups[property] = lookupEditor.Values(typeof(T), property);                var combo = column;                combo.ItemsSource = Lookups[property].ToDictionary(Lookups[property].Columns[0].ColumnName, "Display");                combo.SelectedValuePath = "Key";                combo.DisplayMemberPath = "Value";            }        }        bChanged = false;    }    private void Result_ColumnChanged(object sender, DataColumnChangeEventArgs e)    {        if (_invalidating) return;        if (sender is not DataTable table) return;        var row = GetRow(e.Row);        if (row is null)            return;        var colIdx = table.Columns.IndexOf(e.Column);        if (colIdx < 0 || colIdx >= Parent.Data.Columns.Count)            return;        var data = Parent.Data;        var dataCol = Parent.Data.Columns[colIdx];        var col = ColumnList.OfType<DynamicGridColumn>()            .FirstOrDefault(x => x.ColumnName.Equals(dataCol.ColumnName));                if (col is null)            return;        if (col is DynamicGridCheckBoxColumn<T>)        {            EnsureEditingObject(row);            if(_editingObject is not null)            {                var value = e.Row[e.Column!];                if (value is DBNull)                    value = CoreUtils.GetDefault(dataCol.DataType);                _invalidating = true;                UpdateData(dataCol.ColumnName, new Dictionary<CoreColumn, object?>() { { dataCol, value } });                _invalidating = false;            }            _editingObject = null;        }        if (_editingObject is not null)            bChanged = true;    }    private void CancelEdit()    {        var obj = _editingObject;        bChanged = false;        _editingObject = null;        DataGrid.SelectionController.CurrentCellManager.EndEdit(false);        if(obj is not null)        {            UpdateRow(obj.Row, obj.DataRow);        }    }    private void DataGrid_CurrentCellDropDownSelectionChanged(object? sender,        CurrentCellDropDownSelectionChangedEventArgs e)    {        var row = GetRowFromIndex(e.RowColumnIndex.RowIndex);        if (row is null)            return;        EnsureEditingObject(row);        if ((_editingObject is not null) && (e.SelectedItem is Tuple<object?, string> tuple))        {            var mappedname = DataGrid.Columns[e.RowColumnIndex.ColumnIndex].MappingName;            var colno = DataGridItems.Columns.IndexOf(mappedname);            var corecol = Parent.Data.Columns[colno].ColumnName;            var updates = new Dictionary<CoreColumn, object?>();            var prefix = String.Join(".", corecol.Split(".").Reverse().Skip(1).Reverse());            var field = corecol.Split(".").Last();            var prop = CoreUtils.GetProperty(typeof(T), corecol);            if (prop.GetEditor() is ILookupEditor editor)            {                var data = editor.Values(typeof(T), corecol);                var lookuprow = data.Rows.FirstOrDefault(r => Equals(r[field], tuple.Item1))                    ?? data.NewRow(true);                foreach (CoreColumn lookupcol in data.Columns)                {                    var columnname = String.IsNullOrWhiteSpace(prefix)                        ? lookupcol.ColumnName                        : String.Join(".", prefix, lookupcol.ColumnName);                    var updatecol = Parent.Data.Columns.FirstOrDefault(x => String.Equals(x.ColumnName, columnname));                    if (updatecol != null)                        updates[updatecol] = lookuprow[lookupcol.ColumnName];                }                UpdateData(corecol, updates);                bChanged = true;                            }        }    }    private void DataGrid_CurrentCellEndEdit(object? sender, CurrentCellEndEditEventArgs e)    {        if (_editingObject is not null && bChanged)        {            UpdateData(_editingObject.Row.Index, e.RowColumnIndex.ColumnIndex);        }        if (bChanged)            Parent.DoChanged();        bChanged = false;        _editingObject = null;        // 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        // editing the filter row. It seems that this causes Syncfusion to commit the filter predicates internally, which means that after leaving a         // filter row cell, the filter remained even once it was cleared, meaning a refresh was necessary to get the data back.        // I've tested on Bills to see if editing works with this empty, and it seems so.        //DataGridItems?.AcceptChanges();    }    private void DataGrid_PreviewKeyUp(object sender, KeyEventArgs e)    {        if (e.Key == Key.OemPeriod)        {            if (e.OriginalSource is TimeSpanEdit editor && editor.SelectionStart < 2)            {                editor.SelectionStart = 3;            }        }        else if (e.Key == Key.Tab)        {            if (Parent.IsDirectEditMode())            {                DataGrid.SelectionController.CurrentCellManager.EndEdit();                DataGrid.MoveFocus(new TraversalRequest(FocusNavigationDirection.Right));                DataGrid.SelectionController.CurrentCellManager.BeginEdit();                e.Handled = true;            }        }        else if(e.Key == Key.Escape)        {            if (Parent.IsDirectEditMode())            {                bChanged = false;            }        }    }    #endregion    #region Drag + Drop    private void DataGrid_DragOver(object sender, DragEventArgs e)    {        if (!Parent.Options.DragTarget)        {            return;        }        Parent.DragOver(sender, e);    }    private void DataGrid_Drop(object sender, DragEventArgs e)    {        if (!Parent.Options.DragTarget)        {            return;        }        Parent.Drop(sender, e);    }    private void RowDragDropController_DragStart(object? sender, GridRowDragStartEventArgs e)    {        var rows = e.DraggingRecords.Select(record =>        {            var rowIndex = DataGrid.ResolveToRowIndex(record);            return GetRowFromIndex(rowIndex);        }).NotNull().ToArray();        Parent.DragStart(sender, rows);    }    private void RowDragDropController_Drop(object? sender, GridRowDropEventArgs e)    {        if (!Parent.Options.ReorderRows)        {            e.Handled = true;        }        e.Handled = true;    }    private void RowDragDropController_Dropped(object? sender, GridRowDroppedEventArgs e)    {        if (!Parent.Options.ReorderRows)        {        }        if(e.DropPosition != DropPosition.None)        {            var records = (e.Data.GetData("Records") as ObservableCollection<object>)!;            var targetIdx = (int)e.TargetRecord;            var rows = records.Select(x =>            {                if (x is DataRowView dataRow)                {                    return GetRow(dataRow.Row);                }                else                {                    return null;                }            }).NotNull().OrderBy(x => x.Index).ToArray();            Parent.MoveRows(rows, e.DropPosition == DropPosition.DropBelow ? targetIdx + 1 : targetIdx);        }    }    private void RowDragDropController_DragOver(object? sender, GridRowDragOverEventArgs e)    {        if (!Parent.Options.ReorderRows)        {            e.Handled = true;        }    }    #endregion}
 |