using InABox.Clients; using InABox.Core; using InABox.WPF; using org.omg.PortableInterceptor; 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.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.Data; using System.Windows.Input; using System.Windows.Media; 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 : IDynamicGridUIComponent, IDynamicGridGridUIComponent where T : BaseObject, new() { private readonly Dictionary _filterpredicates = new(); private Dictionary Lookups = new(); private IDynamicGridUIComponentParent _parent; public IDynamicGridUIComponentParent Parent { get => _parent; set { _parent = value; CellBackgroundConverter = new DynamicGridCellStyleConverter(Parent, GetCellBackground); CellForegroundConverter = new DynamicGridCellStyleConverter(Parent, GetCellForeground); CellFontSizeConverter = new DynamicGridCellStyleConverter(Parent, GetCellFontSize); CellFontStyleConverter = new DynamicGridCellStyleConverter(Parent, GetCellFontStyle); CellFontWeightConverter = new DynamicGridCellStyleConverter(Parent, GetCellFontWeight); DataGrid.RowStyleSelector = Parent.RowStyleSelector; DataGrid.TableSummaryRowStyleSelector = new SummaryRowStyleSelector(this, GetSummaryRowStyle); DataGrid.TableSummaryCellStyleSelector = new SummaryCellStyleSelector(this, GetSummaryCellStyle); } } FrameworkElement IDynamicGridUIComponent.Control => DataGrid; #region IDynamicGridGridUIComponent IList IDynamicGridGridUIComponent.ColumnList => ColumnList; int IDynamicGridGridUIComponent.RowHeight => (int)RowHeight; #endregion protected readonly SfDataGrid DataGrid; private readonly ContextMenu ColumnsMenu; private readonly GridRowSizingOptions gridRowResizingOptions = new() { CanIncludeHiddenColumns = false, AutoFitMode = AutoFitMode.Default }; /// /// when is , generally while the grid is refreshing its columns. /// private DataTable? DataGridItems => (DataGrid.ItemsSource as DataTable); private DynamicGridCellStyleConverter CellBackgroundConverter; private DynamicGridCellStyleConverter CellForegroundConverter; private DynamicGridCellStyleConverter CellFontSizeConverter; private DynamicGridCellStyleConverter CellFontStyleConverter; private DynamicGridCellStyleConverter 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; }); DataGrid.CurrentCellBorderThickness = new Thickness(0); DataGrid.AllowFiltering = false; 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); DataGrid.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Visible); DataGrid.FilterChanged += DataGrid_FilterChanged; DataGrid.FilterItemsPopulating += DataGrid_FilterItemsPopulating; 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.MouseMove += DataGrid_MouseMove; DataGrid.CellToolTipOpening += DataGrid_CellToolTipOpening; DataGrid.SizeChanged += DataGrid_SizeChanged; //DataGrid.CellRenderers.Remove("Numeric"); //DataGrid.CellRenderers.Add("Numeric", new CustomNumericCellRenderer(this)); //DataGrid.CellRenderers.Remove("TextBox"); //DataGrid.CellRenderers.Add("TextBox", new CustomTextCellRenderer(this)); } //private class CustomTextCellRenderer : GridCellTextBoxRenderer //{ // private DynamicGridGridUIComponent Component; // public CustomTextCellRenderer(DynamicGridGridUIComponent component) // { // Component = component; // } // public override void OnInitializeEditElement(DataColumnBase dataColumn, TextBox uiElement, object dataContext) // { // base.OnInitializeEditElement(dataColumn, uiElement, dataContext); // uiElement.TextChanged += UiElement_TextChanged; // } // private void UiElement_TextChanged(object sender, TextChangedEventArgs e) // { // throw new NotImplementedException(); // } // private void UiElement_ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) // { // Component.ChangeValue(e.OldValue, e.NewValue); // } //} //private class CustomNumericCellRenderer : GridCellNumericRenderer //{ // private DynamicGridGridUIComponent Component; // public CustomNumericCellRenderer(DynamicGridGridUIComponent component) // { // Component = component; // } // public override void OnInitializeEditElement(DataColumnBase dataColumn, DoubleTextBox uiElement, object dataContext) // { // base.OnInitializeEditElement(dataColumn, uiElement, dataContext); // uiElement.ValueChanged += UiElement_ValueChanged; // } // private void UiElement_ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) // { // Component.ChangeValue(e.OldValue, e.NewValue); // } //} 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(); foreach (var item in DataGrid.SelectedItems) { if (item is DataRowView datarow) { var row = datarow.Row.Table.Rows.IndexOf(datarow.Row); result.Add(Parent.Data.Rows[row]); } } return result.ToArray(); } private void SetSelectedRows(CoreRow[] rows) { DataGrid.SelectedItems.Clear(); var table = DataGridItems; if(table is null) return; var dataRows = rows.Where(x => x.Index > -1).Select(row => { return table.Rows[row.Index]; }); 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(); var table = DataGridItems; if (table is null) return Array.Empty(); var rows = DataGrid.View.Records.Select(x => (x.Data as DataRowView)!).ToList(); foreach (var row in rows) { var iRow = table.Rows.IndexOf(row.Row); result.Add(Parent.Data.Rows[iRow]); } 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! /// /// Get the associated with a given from the Syncfusion DataGrid. /// /// /// 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. /// /// /// 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; var rowIdx = table.Rows.IndexOf(dataRowView.Row); if (rowIdx < 0) return null; return Parent.Data.Rows[rowIdx]; } 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.AllowFiltering = Parent.Options.FilterRows; DataGrid.FilterRowPosition = Parent.Options.FilterRows ? FilterRowPosition.FixedTop : FilterRowPosition.None; if (Parent.Options.DragSource) { if (!DataGrid.AllowDraggingRows) { DataGrid.AllowDraggingRows = true; DataGrid.RowDragDropController.DragStart += RowDragDropController_DragStart; } } else { if (DataGrid.AllowDraggingRows) { DataGrid.AllowDraggingRows = false; DataGrid.RowDragDropController.DragStart -= RowDragDropController_DragStart; } } DataGrid.AllowDrop = Parent.Options.DragTarget; DataGrid.SelectionMode = Parent.Options.MultiSelect ? GridSelectionMode.Extended : GridSelectionMode.Single; return reloadColumns && DataGrid.Columns.Count > 0; } private void DataGrid_FilterChanged(object? o, GridFilterEventArgs e) { var col = DataGrid.Columns.IndexOf(e.Column); if (GetColumn(col) is DynamicActionColumn column) { if (e.FilterPredicates != null) { var filter = e.FilterPredicates.Select(x => x.FilterValue.ToString()!).ToArray(); var include = e.FilterPredicates.Any(x => x.FilterType == FilterType.Equals); if (include) { column.SelectedFilters = filter; column.ExcludeFilters = null; } else if(column.Filters is not null) { column.SelectedFilters = column.Filters.Except(filter).ToArray(); column.ExcludeFilters = null; } else { column.SelectedFilters = null; column.ExcludeFilters = filter; } } else { column.SelectedFilters = null; column.ExcludeFilters = null; } //DataGrid.ClearFilter(e.Column); //e.FilterPredicates?.Clear(); //e.FilterPredicates?.Add(new FilterPredicate() { PredicateType = PredicateType.Or, FilterBehavior = Syncfusion.Data.FilterBehavior.StringTyped, FilterMode = ColumnFilter.DisplayText, FilterType = Syncfusion.Data.FilterType.NotEquals, FilterValue = "" }); //e.FilterPredicates?.Add(new FilterPredicate() { PredicateType = PredicateType.Or, FilterBehavior = Syncfusion.Data.FilterBehavior.StringTyped, FilterMode = ColumnFilter.DisplayText, FilterType = Syncfusion.Data.FilterType.Equals, FilterValue = "" }); //Parent.Refresh(false, false); e.Handled = true; } 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_FilterItemsPopulating(object? sender, GridFilterItemsPopulatingEventArgs e) { var colIdx = DataGrid.Columns.IndexOf(e.Column); var column = GetColumn(colIdx); if(column is not null) { var filterItems = Parent.GetColumnFilterItems(column); if(filterItems is not null) { e.ItemsSource = filterItems.Select(x => { var element = new FilterElement { DisplayText = x, ActualValue = x, }; if(column is DynamicActionColumn dac) { element.IsSelected = (dac.SelectedFilters is null || dac.SelectedFilters.Contains(x)) && (dac.ExcludeFilters is null || !dac.ExcludeFilters.Contains(x)); } return element; }); } else if (column is DynamicActionColumn dac && dac.Filters is not null) { e.ItemsSource = dac.Filters.Select(x => new FilterElement { DisplayText = x, ActualValue = x, IsSelected = (dac.SelectedFilters is null || dac.SelectedFilters.Contains(x)) && (dac.ExcludeFilters is null || !dac.ExcludeFilters.Contains(x)) }); } } } private void DataGrid_CellToolTipOpening(object? sender, GridCellToolTipOpeningEventArgs e) { if (GetColumn(e.RowColumnIndex.ColumnIndex) is not DynamicActionColumn col) return; var toolTip = col.ToolTip; if (toolTip is null) return; var row = GetRowFromIndex(e.RowColumnIndex.RowIndex); e.ToolTip.Template = TemplateGenerator.CreateControlTemplate( typeof(ToolTip), () => toolTip.Invoke(col, row) ); } 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>> GetFilterPredicates() { var list = new List>>(); foreach (var column in DataGrid.Columns) { var colIndex = DataGrid.Columns.IndexOf(column); var col = ColumnList[colIndex]; if (col is DynamicGridColumn gridColumn) { var rowPredicate = DynamicGridGridUIComponentExtension.ConvertColumnPredicates(gridColumn, column.FilterPredicates); if(rowPredicate is not null) { list.Add(new(gridColumn.ColumnName, rowPredicate)); } } else if(col is DynamicActionColumn dac && dac.FilterRecord is not null) { if(dac.SelectedFilters is not null && dac.SelectedFilters.Length > 0) { list.Add(new(column.MappingName, (row) => dac.FilterRecord(row, dac.SelectedFilters))); } if(dac.ExcludeFilters is not null && dac.ExcludeFilters.Length > 0) { list.Add(new(column.MappingName, (row) => !dac.FilterRecord(row, dac.ExcludeFilters))); } } } return list; } public void ScrollIntoView(CoreRow row) { var rowIdx = DataGrid.ResolveToRowIndex(row.Index + 1); DataGrid.ScrollInView(new RowColumnIndex(rowIdx, 0)); } 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 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) { var template = new ControlTemplate(typeof(GridHeaderCellControl)); var border = new FrameworkElementFactory(typeof(Border)); border.SetValue(Border.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)); border.SetValue(Border.PaddingProperty, new Thickness(4)); var img = new FrameworkElementFactory(typeof(Image)); img.SetValue(Image.SourceProperty, image); border.AppendChild(img); template.VisualTree = border; headStyle.Setters.Add(new Setter(Control.TemplateProperty, template)); } } } 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 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 { 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; } #region Columns private class StackedHeaderRenderer : GridStackedHeaderCellRenderer { private Style Style; public StackedHeaderRenderer() { 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))); Style = headstyle; } public override void OnInitializeEditElement(DataColumnBase dataColumn, GridStackedHeaderCellControl uiElement, object dataContext) { uiElement.Style = Style; base.OnInitializeEditElement(dataColumn, uiElement, dataContext); } } private void LoadStackedHeaders(DynamicGridColumnGroupings groupings) { DataGrid.StackedHeaderRows.Clear(); 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 stackedColumn = new StackedColumn { HeaderText = group.Header, ChildColumns = string.Join(',', cols.Select(x => x.MappingName)) }; 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()); } } private readonly List ColumnList = new(); private List ActionColumns = new(); private DynamicColumnBase? GetColumn(int index) => index >= 0 && index < ColumnList.Count ? ColumnList[index] : null; int IDynamicGridUIComponent.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 Summaries = new(); private void LoadActionColumns(DynamicActionColumnPosition position) { for (var i = 0; i < ActionColumns.Count; i++) { var column = ActionColumns[i]; if (column.Position == position) { //String sColName = String.Format("ActionColumn{0}{1}", i, position == DynamicActionColumnPosition.Start ? "L" : "R"); var sColName = string.Format("ActionColumn{0}", i); gridRowResizingOptions.ExcludeColumns.Add(sColName); var summary = 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.Stretch = Stretch.Uniform; 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; ApplyFilterStyle(newcol, true, true); 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); 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 == Alignment.NotSet ? TextAlignment.Left : txtCol.Alignment == Alignment.BottomLeft || txtCol.Alignment == Alignment.MiddleLeft || txtCol.Alignment == Alignment.TopLeft ? TextAlignment.Left : txtCol.Alignment == Alignment.BottomCenter || txtCol.Alignment == Alignment.MiddleCenter || txtCol.Alignment == Alignment.TopCenter ? TextAlignment.Center : TextAlignment.Right; newcol.AllowEditing = false; newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged; newcol.MappingName = sColName; newcol.Width = column.Width; newcol.ColumnSizer = GridLengthUnitType.None; newcol.HeaderText = column.HeaderText; newcol.AllowFiltering = (column.Filters != null && column.Filters.Length != 0) || column.FilterRecord is not null; newcol.AllowSorting = false; newcol.FilterRowOptionsVisibility = Visibility.Collapsed; newcol.ShowHeaderToolTip = column.ToolTip != null; 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 = new Style(); cellstyle.Setters.Add(new Setter(Control.BackgroundProperty, new Binding() { Path = new PropertyPath("."), Converter = CellBackgroundConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); cellstyle.Setters.Add(new Setter(Control.ForegroundProperty, new Binding() { Converter = CellForegroundConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); cellstyle.Setters.Add(new Setter(Control.FontSizeProperty, new Binding() { Converter = CellFontSizeConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); cellstyle.Setters.Add(new Setter(Control.FontStyleProperty, new Binding() { Converter = CellFontStyleConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); cellstyle.Setters.Add(new Setter(Control.FontWeightProperty, new Binding() { Converter = CellFontWeightConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); newcol.CellStyle = cellstyle; DataGrid.Columns.Add(newcol); ColumnList.Add(column); } else if (column is DynamicTemplateColumn tmplCol) { var newcol = new GridTemplateColumn(); newcol.CellTemplateSelector = new TemplateColumnSelector(this, tmplCol.Template); newcol.AllowEditing = false; newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged; newcol.MappingName = sColName; newcol.Width = tmplCol.Width; newcol.ColumnSizer = GridLengthUnitType.None; newcol.HeaderText = column.HeaderText; newcol.AllowFiltering = false; newcol.AllowSorting = false; newcol.FilterRowOptionsVisibility = Visibility.Collapsed; 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 = new Style(); cellstyle.Setters.Add(new Setter(Control.BackgroundProperty, new Binding() { Path = new PropertyPath("."), Converter = CellBackgroundConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); cellstyle.Setters.Add(new Setter(Control.ForegroundProperty, new Binding() { Converter = CellForegroundConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); cellstyle.Setters.Add(new Setter(Control.FontSizeProperty, new Binding() { Converter = CellFontSizeConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); cellstyle.Setters.Add(new Setter(Control.FontStyleProperty, new Binding() { Converter = CellFontStyleConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); cellstyle.Setters.Add(new Setter(Control.FontWeightProperty, new Binding() { Converter = CellFontWeightConverter, ConverterParameter = new DynamicGridCellStyleParameters(column,DependencyProperty.UnsetValue) })); newcol.CellStyle = cellstyle; DataGrid.Columns.Add(newcol); ColumnList.Add(column); } } } } public class SummaryRowStyleSelector(DynamicGridGridUIComponent parent, Func