|
@@ -22,6 +22,7 @@ using System.Windows.Media;
|
|
|
using System.Windows.Media.Imaging;
|
|
|
using Syncfusion.UI.Xaml.TreeGrid.Filtering;
|
|
|
using Syncfusion.UI.Xaml.TreeGrid.Cells;
|
|
|
+using System.Windows.Controls.Primitives;
|
|
|
|
|
|
namespace InABox.DynamicGrid;
|
|
|
|
|
@@ -67,6 +68,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
|
|
|
private ContextMenu _menu;
|
|
|
private SfTreeGrid _tree;
|
|
|
+ private Grid _summaryRow;
|
|
|
private readonly ContextMenu ColumnsMenu;
|
|
|
|
|
|
public event OnContextMenuOpening OnContextMenuOpening;
|
|
@@ -181,13 +183,6 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
private DynamicGridCellStyleConverter<System.Windows.FontStyle?> CellFontStyleConverter;
|
|
|
private DynamicGridCellStyleConverter<System.Windows.FontWeight?> CellFontWeightConverter;
|
|
|
|
|
|
- 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;
|
|
|
-
|
|
|
-
|
|
|
public DynamicGridTreeUIComponent(Expression<Func<T, Guid>> idColumn, Expression<Func<T, Guid>> parentIDColumn)
|
|
|
{
|
|
|
IDColumn = new Column<T>(CoreUtils.GetFullPropertyName(idColumn, "."));
|
|
@@ -216,6 +211,8 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
_tree.CellDoubleTapped += _tree_CellDoubleTapped;
|
|
|
_tree.KeyUp += _tree_KeyUp;
|
|
|
|
|
|
+ _tree.Loaded += _tree_Loaded;
|
|
|
+
|
|
|
_tree.CellToolTipOpening += _tree_CellToolTipOpening;
|
|
|
|
|
|
_menu = new ContextMenu();
|
|
@@ -272,6 +269,90 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
_tree.SizeChanged += _tree_SizeChanged;
|
|
|
}
|
|
|
|
|
|
+ private void _tree_Loaded(object sender, RoutedEventArgs e)
|
|
|
+ {
|
|
|
+ _summaryRow = new Grid();
|
|
|
+ _summaryRow.Visibility = Visibility.Collapsed;
|
|
|
+
|
|
|
+ var scroll = _tree.FindChild<ScrollViewer>("PART_ScrollViewer");
|
|
|
+ if(scroll is not null)
|
|
|
+ {
|
|
|
+ var grid = scroll.FindVisualChildren<Grid>(recursive: false).FirstOrDefault();
|
|
|
+ if(grid is not null)
|
|
|
+ {
|
|
|
+ var row1 = grid.RowDefinitions[0];
|
|
|
+ var row2 = grid.RowDefinitions[1];
|
|
|
+ grid.RowDefinitions.Clear();
|
|
|
+ grid.RowDefinitions.Add(row1);
|
|
|
+ var rowDef = grid.AddRow(GridUnitType.Auto);
|
|
|
+
|
|
|
+ grid.RowDefinitions.Add(row2);
|
|
|
+
|
|
|
+ foreach(var child in grid.Children.OfType<UIElement>())
|
|
|
+ {
|
|
|
+ var row = Grid.GetRow(child);
|
|
|
+ if(row >= 1)
|
|
|
+ {
|
|
|
+ Grid.SetRow(child, row + 1);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var rowSpan = Grid.GetRowSpan(child);
|
|
|
+ if(row + rowSpan >= 1 && child is ScrollBar)
|
|
|
+ {
|
|
|
+ Grid.SetRowSpan(child, rowSpan + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var horizontalScrollbar = grid.Children.OfType<ScrollBar>().First(x => x.Orientation == Orientation.Horizontal);
|
|
|
+
|
|
|
+ var treeGridPanel = scroll.FindChild<TreeGridPanel>("PART_TreeGridPanel");
|
|
|
+
|
|
|
+ var summaryScroll = new ScrollViewer
|
|
|
+ {
|
|
|
+ VerticalScrollBarVisibility = ScrollBarVisibility.Hidden,
|
|
|
+ HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden
|
|
|
+ };
|
|
|
+ summaryScroll.Content = _summaryRow;
|
|
|
+
|
|
|
+ scroll.ScrollChanged += (o, e) =>
|
|
|
+ {
|
|
|
+ summaryScroll.ScrollToHorizontalOffset(scroll.HorizontalOffset);
|
|
|
+
|
|
|
+ var panel = treeGridPanel;
|
|
|
+ };
|
|
|
+
|
|
|
+ var transform = new TranslateTransform();
|
|
|
+ summaryScroll.RenderTransform = transform;
|
|
|
+
|
|
|
+ void UpdateSize(double height)
|
|
|
+ {
|
|
|
+ var desiredHeight = treeGridPanel.RowHeights.TotalExtent;
|
|
|
+ if(desiredHeight < height)
|
|
|
+ {
|
|
|
+ var diff = height - desiredHeight;
|
|
|
+ transform.Y = -diff - 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ transform.Y = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ treeGridPanel.SizeChanged += (o, e) =>
|
|
|
+ {
|
|
|
+ UpdateSize(e.NewSize.Height);
|
|
|
+ };
|
|
|
+ _tree.FilterChanged += (o, e) =>
|
|
|
+ {
|
|
|
+ UpdateSize(treeGridPanel.ActualHeight);
|
|
|
+ };
|
|
|
+
|
|
|
+ grid.AddChild(summaryScroll, 1, 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private class TreeGridSelectionControllerExt(SfTreeGrid treeGrid, DynamicGridTreeUIComponent<T> grid) : TreeGridRowSelectionController(treeGrid)
|
|
|
{
|
|
|
private DynamicGridTreeUIComponent<T> Grid = grid;
|
|
@@ -496,6 +577,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
Parent.UIFilterChanged(this);
|
|
|
|
|
|
UpdateRecordCount();
|
|
|
+ CalculateSummaries();
|
|
|
}
|
|
|
|
|
|
public void AddVisualFilter(string column, string value, FilterType filtertype = FilterType.Contains)
|
|
@@ -604,6 +686,88 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ #region Styles
|
|
|
+
|
|
|
+ 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 Brush? GetCellSelectionForegroundBrush() => DynamicGridUtils.SelectionForeground;
|
|
|
+ protected virtual Brush? GetCellSelectionBackgroundBrush() => DynamicGridUtils.SelectionBackground;
|
|
|
+
|
|
|
+ protected virtual Style GetHeaderCellStyle(DynamicColumnBase column)
|
|
|
+ {
|
|
|
+ var headStyle = new Style(typeof(TreeGridHeaderCell));
|
|
|
+
|
|
|
+ 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 GetSummaryCellStyle(DynamicColumnBase column)
|
|
|
+ {
|
|
|
+ var style = new Style(typeof(SummaryCellControl));
|
|
|
+
|
|
|
+ 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.VerticalContentAlignmentProperty, VerticalAlignment.Center));
|
|
|
+
|
|
|
+ style.Setters.Add(new Setter(Control.BorderBrushProperty, new SolidColorBrush(Colors.Gray)));
|
|
|
+ style.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0, 0.75, 0.75, 0.0)));
|
|
|
+ style.Setters.Add(new Setter(Control.FontSizeProperty, 12D));
|
|
|
+ style.Setters.Add(new Setter(Control.FontWeightProperty, FontWeights.DemiBold));
|
|
|
+
|
|
|
+ style.Setters.Add(new Setter(Control.PaddingProperty, new Thickness(4)));
|
|
|
+
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
#region Sizing
|
|
|
|
|
|
public double RowHeight
|
|
@@ -754,6 +918,8 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
|
|
|
private List<DynamicActionColumn> ActionColumns = new();
|
|
|
|
|
|
+ private List<Summary> Summaries = new();
|
|
|
+
|
|
|
private readonly Dictionary<string, string> FilterPredicates = new();
|
|
|
|
|
|
private DynamicColumnBase? GetColumn(int index) =>
|
|
@@ -812,6 +978,12 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
{
|
|
|
var sColName = $"[_ActionColumn{i}]";
|
|
|
|
|
|
+ var summary = column.Summary();
|
|
|
+ if(summary is not null)
|
|
|
+ {
|
|
|
+ Summaries.Add(new(column, summary, null, null));
|
|
|
+ }
|
|
|
+
|
|
|
if (column is DynamicImageColumn imgcol)
|
|
|
{
|
|
|
var newcol = new TreeGridTemplateColumn();
|
|
@@ -840,40 +1012,9 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
newcol.ShowToolTip = column.ToolTip != null;
|
|
|
newcol.ShowHeaderToolTip = column.ToolTip != null;
|
|
|
|
|
|
- var headstyle = new Style(typeof(TreeGridHeaderCell));
|
|
|
- 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));
|
|
|
+ var headstyle = GetHeaderCellStyle(column);
|
|
|
headstyle.Setters.Add(new EventSetter(Control.MouseLeftButtonUpEvent, new MouseButtonEventHandler(HeaderCell_LeftMouseButtonEvent)));
|
|
|
- if (!string.IsNullOrWhiteSpace(column.HeaderText))
|
|
|
- {
|
|
|
- //headstyle.Setters.Add(new Setter(LayoutTransformProperty, new RotateTransform(270.0F)));
|
|
|
- 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)));
|
|
|
- if (imgcol.VerticalHeader)
|
|
|
- headstyle.Setters.Add(new Setter(Control.TemplateProperty,
|
|
|
- Application.Current.Resources["VerticalColumnHeader"] as ControlTemplate));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- var image = imgcol.Image?.Invoke(null);
|
|
|
- if (image != null)
|
|
|
- {
|
|
|
- var template = new DataTemplate(typeof(TreeGridHeaderCell));
|
|
|
- var border = new FrameworkElementFactory(typeof(Border));
|
|
|
- border.SetValue(Border.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro));
|
|
|
- border.SetValue(Border.PaddingProperty, new Thickness(4));
|
|
|
- border.SetValue(Control.MarginProperty, new Thickness(0, 0, 1, 1));
|
|
|
- var img = new FrameworkElementFactory(typeof(Image));
|
|
|
- img.SetValue(Image.SourceProperty, image);
|
|
|
- border.AppendChild(img);
|
|
|
- template.VisualTree = border;
|
|
|
- headstyle.Setters.Add(new Setter(TreeGridHeaderCell.PaddingProperty, new Thickness(0)));
|
|
|
- headstyle.Setters.Add(new Setter(TreeGridHeaderCell.ContentTemplateProperty, template));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- newcol.HeaderStyle = headstyle;
|
|
|
+ newcol.HeaderStyle = GetHeaderCellStyle(column);
|
|
|
|
|
|
_tree.Columns.Add(newcol);
|
|
|
ColumnList.Add(column);
|
|
@@ -905,20 +1046,8 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
|
|
|
ApplyFilterStyle(newcol, false, true);
|
|
|
|
|
|
- var headstyle = new Style(typeof(TreeGridHeaderCell));
|
|
|
- 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.MarginProperty, new Thickness(0, -0.75, 0, 0.75)));
|
|
|
- headstyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0.75)));
|
|
|
+ var headstyle = GetHeaderCellStyle(column);
|
|
|
headstyle.Setters.Add(new EventSetter(Control.MouseLeftButtonUpEvent, new MouseButtonEventHandler(HeaderCell_LeftMouseButtonEvent)));
|
|
|
- if (txtCol.VerticalHeader)
|
|
|
- {
|
|
|
- headstyle.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Left));
|
|
|
- headstyle.Setters.Add(new Setter(Control.TemplateProperty,
|
|
|
- Application.Current.Resources["VerticalColumnHeader"] as ControlTemplate));
|
|
|
- }
|
|
|
-
|
|
|
newcol.HeaderStyle = headstyle;
|
|
|
|
|
|
_tree.Columns.Add(newcol);
|
|
@@ -942,12 +1071,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
|
|
|
ApplyFilterStyle(newcol, false, true);
|
|
|
|
|
|
- var headstyle = new Style(typeof(TreeGridHeaderCell));
|
|
|
- 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.MarginProperty, new Thickness(0, -0.75, 0, 0.75)));
|
|
|
- headstyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0.75)));
|
|
|
+ var headstyle = GetHeaderCellStyle(column);
|
|
|
headstyle.Setters.Add(new EventSetter(Control.MouseLeftButtonUpEvent, new MouseButtonEventHandler(HeaderCell_LeftMouseButtonEvent)));
|
|
|
newcol.HeaderStyle = headstyle;
|
|
|
|
|
@@ -969,13 +1093,15 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
|
|
|
var newColumn = newcol.CreateTreeGridColumn();
|
|
|
|
|
|
+ var summary = newcol.Summary();
|
|
|
+ if(summary is not null)
|
|
|
+ {
|
|
|
+ Summaries.Add(new(column, summary, null, null));
|
|
|
+ }
|
|
|
+
|
|
|
ApplyFilterStyle(newColumn, newcol.Filtered, false);
|
|
|
|
|
|
- var headstyle = new Style(typeof(TreeGridHeaderCell));
|
|
|
- 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));
|
|
|
- newColumn.HeaderStyle = headstyle;
|
|
|
+ newColumn.HeaderStyle = GetHeaderCellStyle(column);
|
|
|
|
|
|
var cellstyle = new Style();
|
|
|
if (Parent.IsDirectEditMode())
|
|
@@ -1086,6 +1212,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
|
|
|
ColumnList.Clear();
|
|
|
_tree.Columns.Clear();
|
|
|
+ Summaries.Clear();
|
|
|
|
|
|
ActionColumns = actionColumns.ToList();
|
|
|
|
|
@@ -1130,12 +1257,164 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
grid.Dispatcher.BeginInvoke(() =>
|
|
|
{
|
|
|
foreach (var (index, size) in this.CalculateColumnSizes(width))
|
|
|
- _tree.Columns[index].Width = Math.Max(0.0F, size);
|
|
|
+ {
|
|
|
+ var colSize = Math.Max(0.0F, size);
|
|
|
+ _tree.Columns[index].Width = colSize;
|
|
|
+ }
|
|
|
+
|
|
|
+ RebuildSummaryRow();
|
|
|
});
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
+ #region Summary
|
|
|
+
|
|
|
+ private class Summary(DynamicColumnBase column, IDynamicGridSummary summary, SummaryCellControl? control, object? data)
|
|
|
+ {
|
|
|
+ public DynamicColumnBase Column { get; set; } = column;
|
|
|
+
|
|
|
+ public IDynamicGridSummary SummaryDefinition { get; set; } = summary;
|
|
|
+
|
|
|
+ public SummaryCellControl? Control { get; set; } = control;
|
|
|
+
|
|
|
+ public object? Data { get; set; } = data;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected class SummaryCellControl : ContentControl
|
|
|
+ {
|
|
|
+ public SummaryCellControl()
|
|
|
+ {
|
|
|
+ var template = new ControlTemplate(typeof(ContentControl));
|
|
|
+
|
|
|
+ var factory = new FrameworkElementFactory(typeof(Border));
|
|
|
+ factory.Bind<ContentControl, Brush>(Border.BorderBrushProperty, x => x.BorderBrush);
|
|
|
+ factory.Bind<ContentControl, Thickness>(Border.BorderThicknessProperty, x => x.BorderThickness);
|
|
|
+ factory.Bind<ContentControl, Brush>(Border.BackgroundProperty, x => x.Background);
|
|
|
+ factory.Bind<ContentControl, Thickness>(Border.PaddingProperty, x => x.Padding);
|
|
|
+
|
|
|
+ var content = new FrameworkElementFactory(typeof(ContentPresenter));
|
|
|
+ content.Bind<ContentControl, HorizontalAlignment>(ContentPresenter.HorizontalAlignmentProperty, x => x.HorizontalContentAlignment);
|
|
|
+ content.Bind<ContentControl, VerticalAlignment>(ContentPresenter.VerticalAlignmentProperty, x => x.VerticalContentAlignment);
|
|
|
+ factory.AppendChild(content);
|
|
|
+ template.VisualTree = factory;
|
|
|
+
|
|
|
+ Template = template;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void RebuildSummaryRow()
|
|
|
+ {
|
|
|
+ _summaryRow.RowDefinitions.Clear();
|
|
|
+ _summaryRow.ColumnDefinitions.Clear();
|
|
|
+ _summaryRow.Children.Clear();
|
|
|
+
|
|
|
+ var row = _summaryRow.AddRow(GridUnitType.Auto);
|
|
|
+ row.MinHeight = _tree.RowHeight;
|
|
|
+
|
|
|
+ foreach(var (i, column) in _tree.Columns.WithIndex())
|
|
|
+ {
|
|
|
+ _summaryRow.AddColumn(column.ActualWidth);
|
|
|
+
|
|
|
+ var cell = new SummaryCellControl();
|
|
|
+ if(GetColumn(i) is DynamicColumnBase col)
|
|
|
+ {
|
|
|
+ cell.Style = GetSummaryCellStyle(col);
|
|
|
+
|
|
|
+ var summary = Summaries.FirstOrDefault(x => x.Column == col);
|
|
|
+ if(summary is not null)
|
|
|
+ {
|
|
|
+ cell.Content = summary.Data;
|
|
|
+ summary.Control = cell;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _summaryRow.AddChild(cell, 0, _summaryRow.ColumnDefinitions.Count - 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void CalculateSummaries()
|
|
|
+ {
|
|
|
+ foreach(var column in ColumnList)
|
|
|
+ {
|
|
|
+ CalculateSummary(column);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private object? CalculateSummaryData(IDynamicGridSummary summary, DynamicColumnBase column)
|
|
|
+ {
|
|
|
+ if(summary is DynamicGridCountSummary count)
|
|
|
+ {
|
|
|
+ return string.Format("{0:N0}", _tree.View.Nodes.Count);
|
|
|
+ }
|
|
|
+ else if(summary is DynamicGridSumSummary sum)
|
|
|
+ {
|
|
|
+ if(column is DynamicGridColumn gridColumn)
|
|
|
+ {
|
|
|
+ var data = _tree.View.Nodes.Select(x => MapRow((x.Item as CoreTreeNode)?.Row)).NotNull()
|
|
|
+ .Select(x => x[gridColumn.ColumnName]);
|
|
|
+
|
|
|
+ object? result;
|
|
|
+ if(sum.AggregateType == typeof(double))
|
|
|
+ {
|
|
|
+ result = data.Sum(x => x is double d ? d : 0);
|
|
|
+ }
|
|
|
+ else if(sum.AggregateType == typeof(int))
|
|
|
+ {
|
|
|
+ result = data.Sum(x => x is int i ? i : 0);
|
|
|
+ }
|
|
|
+ else if(sum.AggregateType == typeof(TimeSpan))
|
|
|
+ {
|
|
|
+ result = data.Aggregate(TimeSpan.Zero, (cur, x) => x is TimeSpan ts ? cur + ts : cur);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result = null;
|
|
|
+ }
|
|
|
+ if(result is not null)
|
|
|
+ {
|
|
|
+ return string.Format($"{{0:{sum.Format}}}", result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if(summary is DynamicGridCustomSummary custom)
|
|
|
+ {
|
|
|
+ var data = _tree.View.Nodes.Select(x => MapRow((x.Item as CoreTreeNode)?.Row)).NotNull();
|
|
|
+ var result = custom.Aggregate(data);
|
|
|
+ if(result is not null)
|
|
|
+ {
|
|
|
+ return string.Format($"{{0:{custom.Format}}}", result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if(summary is DynamicGridTemplateSummary template)
|
|
|
+ {
|
|
|
+ return template.Template();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void CalculateSummary(DynamicColumnBase column)
|
|
|
+ {
|
|
|
+ var (idx, summary) = Summaries.WithIndex().FirstOrDefault(x => x.Value.Column == column);
|
|
|
+ if(summary is null)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var colIdx = ColumnList.IndexOf(summary.Column);
|
|
|
+ if(colIdx == -1)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ summary.Data = CalculateSummaryData(summary.SummaryDefinition, column);
|
|
|
+
|
|
|
+ if(summary.Control is not null)
|
|
|
+ {
|
|
|
+ summary.Control.Content = summary.Data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
#region Refresh
|
|
|
|
|
|
public CoreTreeNodes Nodes { get; set; }
|
|
@@ -1145,8 +1424,12 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
|
|
|
public void BeforeRefresh()
|
|
|
{
|
|
|
- _tree.SelectionForeground = DynamicGridUtils.SelectionForeground;
|
|
|
- _tree.SelectionBackground = DynamicGridUtils.SelectionBackground;
|
|
|
+ if(_summaryRow is not null)
|
|
|
+ {
|
|
|
+ _summaryRow.Visibility = Visibility.Collapsed;
|
|
|
+ }
|
|
|
+ _tree.SelectionForeground = GetCellSelectionForegroundBrush();
|
|
|
+ _tree.SelectionBackground = GetCellSelectionBackgroundBrush();
|
|
|
}
|
|
|
|
|
|
public void RefreshData(CoreTable data)
|
|
@@ -1181,6 +1464,9 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
nodes.ColumnChanged += Nodes_ColumnChanged;
|
|
|
Nodes = nodes;
|
|
|
_tree.ItemsSource = nodes.Nodes;
|
|
|
+ _summaryRow.Visibility = Visibility.Visible;
|
|
|
+
|
|
|
+ CalculateSummaries();
|
|
|
|
|
|
CalculateRowHeight();
|
|
|
ResizeColumns(_tree, _tree.ActualWidth - 1, _tree.ActualHeight);
|
|
@@ -1203,6 +1489,7 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
var _parent = row.Get<Guid>(ParentColumn.Property);
|
|
|
Nodes.Add(_id, _parent, newRow);
|
|
|
}
|
|
|
+ CalculateSummaries();
|
|
|
|
|
|
CalculateRowHeight();
|
|
|
UpdateRecordCount();
|
|
@@ -1456,6 +1743,8 @@ public class DynamicGridTreeUIComponent<T> : IDynamicGridUIComponent<T>, IDynami
|
|
|
if (col is null || dataCol is null)
|
|
|
return;
|
|
|
|
|
|
+ CalculateSummary(col);
|
|
|
+
|
|
|
if (col is DynamicGridCheckBoxColumn<T>)
|
|
|
{
|
|
|
EnsureEditingObject(row);
|