From cccf90193e4ede40200bf741fe6db4d21782365f Mon Sep 17 00:00:00 2001 From: CHINBOY Date: Wed, 28 May 2025 22:55:27 +0800 Subject: [PATCH] Add DataGridCell --- .../Cell/DataGridCell.cs | 224 ++++++++++++ .../Cell/DataGridCellsPresenter.cs | 335 ++++++++++++++++++ .../DataGrid.Cells.cs | 57 +++ src/AtomUI.Controls.DataGrid/DataGrid.cs | 14 +- .../Row/DataGridRowGroupInfo.cs | 4 +- .../Theme/DataGridCellTheme.cs | 2 + 6 files changed, 627 insertions(+), 9 deletions(-) create mode 100644 src/AtomUI.Controls.DataGrid/DataGrid.Cells.cs diff --git a/src/AtomUI.Controls.DataGrid/Cell/DataGridCell.cs b/src/AtomUI.Controls.DataGrid/Cell/DataGridCell.cs index 2b9713a17..d061e8eaf 100644 --- a/src/AtomUI.Controls.DataGrid/Cell/DataGridCell.cs +++ b/src/AtomUI.Controls.DataGrid/Cell/DataGridCell.cs @@ -1,8 +1,232 @@ +// (c) Copyright Microsoft Corporation. +// This source is subject to the Microsoft Public License (Ms-PL). +// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. +// All other rights reserved. + +using System.Diagnostics; +using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Metadata; +using Avalonia.Controls.Primitives; +using Avalonia.Controls.Shapes; +using Avalonia.Input; namespace AtomUI.Controls; +[TemplatePart(DataGridCellTheme.RightGridLinePart, typeof(Rectangle))] +[PseudoClasses(StdPseudoClass.Selected, StdPseudoClass.Current, StdPseudoClass.Edited, StdPseudoClass.Invalid, StdPseudoClass.Focus)] public class DataGridCell : ContentControl { + #region 公共属性定义 + + public static readonly DirectProperty IsValidProperty = + AvaloniaProperty.RegisterDirect( + nameof(IsValid), + o => o.IsValid); + bool _isValid = true; + public bool IsValid + { + get => _isValid; + internal set => SetAndRaise(IsValidProperty, ref _isValid, value); + } + + #endregion + + #region 内部属性定义 + + internal DataGridRow? OwningRow { get; set; } + + private DataGridColumn? _owningColumn; + internal DataGridColumn? OwningColumn + { + get => _owningColumn; + set + { + if (_owningColumn != value) + { + _owningColumn = value; + OnOwningColumnSet(value); + } + } + } + + internal DataGrid? OwningGrid => OwningRow?.OwningGrid ?? OwningColumn?.OwningGrid; + + internal double ActualRightGridLineWidth => _rightGridLine?.Bounds.Width ?? 0; + + internal int ColumnIndex => OwningColumn?.Index ?? -1; + internal int RowIndex => OwningRow?.Index ?? -1; + + internal bool IsCurrent => OwningGrid != null && + OwningColumn != null && + OwningRow != null && + OwningGrid.CurrentColumnIndex == OwningColumn.Index && + OwningGrid.CurrentSlot == OwningRow.Slot; + + private bool IsEdited => OwningGrid != null && + OwningGrid.EditingRow == OwningRow && + OwningGrid.EditingColumnIndex == ColumnIndex; + + private bool IsMouseOver + { + get => OwningRow != null && OwningRow.MouseOverColumnIndex == ColumnIndex; + set + { + Debug.Assert(OwningRow != null); + if (value != IsMouseOver) + { + if (value) + { + OwningRow.MouseOverColumnIndex = ColumnIndex; + } + else + { + OwningRow.MouseOverColumnIndex = null; + } + } + } + } + + #endregion + + private Rectangle? _rightGridLine; + + /// + /// Builds the visual tree for the cell control when a new template is applied. + /// + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + UpdatePseudoClasses(); + _rightGridLine = e.NameScope.Find(DataGridCellTheme.RightGridLinePart); + if (_rightGridLine != null && OwningColumn == null) + { + // Turn off the right GridLine for filler cells + _rightGridLine.IsVisible = false; + } + else + { + EnsureGridLine(null); + } + } + protected override void OnPointerEntered(PointerEventArgs e) + { + base.OnPointerEntered(e); + + if (OwningRow != null) + { + IsMouseOver = true; + } + } + protected override void OnPointerExited(PointerEventArgs e) + { + base.OnPointerExited(e); + + if (OwningRow != null) + { + IsMouseOver = false; + } + } + + //TODO TabStop + private void HandlePointerPressed(PointerPressedEventArgs e) + { + // OwningGrid is null for TopLeftHeaderCell and TopRightHeaderCell because they have no OwningRow + if (OwningGrid == null || OwningColumn == null || OwningRow == null) + { + return; + } + OwningGrid.NotifyCellPointerPressed(new DataGridCellPointerPressedEventArgs(this, OwningRow, OwningColumn, e)); + if (e.Handled) + { + return; + } + if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) + { + if (OwningGrid.IsTabStop) + { + OwningGrid.Focus(); + } + if (OwningRow != null) + { + var handled = OwningGrid.UpdateStateOnMouseLeftButtonDown(e, ColumnIndex, OwningRow.Slot, !e.Handled); + + // Do not handle PointerPressed with touch or pen, + // so we can start scroll gesture on the same event. + if (e.Pointer.Type != PointerType.Touch && e.Pointer.Type != PointerType.Pen) + { + e.Handled = handled; + } + } + } + else if (e.GetCurrentPoint(this).Properties.IsRightButtonPressed) + { + if (OwningGrid.IsTabStop) + { + OwningGrid.Focus(); + } + if (OwningRow != null) + { + e.Handled = OwningGrid.UpdateStateOnMouseRightButtonDown(e, ColumnIndex, OwningRow.Slot, !e.Handled); + } + } + } + + internal void UpdatePseudoClasses() + { + if (OwningGrid == null || OwningColumn == null || OwningRow == null || !OwningRow.IsVisible || OwningRow.Slot == -1) + { + return; + } + + PseudoClasses.Set(":selected", OwningRow.IsSelected); + + PseudoClasses.Set(":current", IsCurrent); + + PseudoClasses.Set(":edited", IsEdited); + + PseudoClasses.Set(":invalid", !IsValid); + + PseudoClasses.Set(":focus", OwningGrid.IsFocused && IsCurrent); + } + + // Makes sure the right gridline has the proper stroke and visibility. If lastVisibleColumn is specified, the + // right gridline will be collapsed if this cell belongs to the lastVisibleColumn and there is no filler column + internal void EnsureGridLine(DataGridColumn? lastVisibleColumn) + { + if (OwningGrid != null && _rightGridLine != null) + { + if (OwningGrid.VerticalGridLinesBrush != null && OwningGrid.VerticalGridLinesBrush != _rightGridLine.Fill) + { + _rightGridLine.Fill = OwningGrid.VerticalGridLinesBrush; + } + + bool newVisibility = + (OwningGrid.GridLinesVisibility == DataGridGridLinesVisibility.Vertical || OwningGrid.GridLinesVisibility == DataGridGridLinesVisibility.All) + && ((OwningGrid.ColumnsInternal.FillerColumn != null && OwningGrid.ColumnsInternal.FillerColumn.IsActive) || OwningColumn != lastVisibleColumn); + + if (newVisibility != _rightGridLine.IsVisible) + { + _rightGridLine.IsVisible = newVisibility; + } + } + } + + private void OnOwningColumnSet(DataGridColumn? column) + { + if (column == null) + { + Classes.Clear(); + ClearValue(ThemeProperty); + } + else + { + if (Theme != column.CellTheme) + { + Theme = column.CellTheme; + } + + Classes.Replace(column.CellStyleClasses); + } + } } \ No newline at end of file diff --git a/src/AtomUI.Controls.DataGrid/Cell/DataGridCellsPresenter.cs b/src/AtomUI.Controls.DataGrid/Cell/DataGridCellsPresenter.cs index 07ab7e8fe..e831794a3 100644 --- a/src/AtomUI.Controls.DataGrid/Cell/DataGridCellsPresenter.cs +++ b/src/AtomUI.Controls.DataGrid/Cell/DataGridCellsPresenter.cs @@ -1,9 +1,344 @@ +// (c) Copyright Microsoft Corporation. +// This source is subject to the Microsoft Public License (Ms-PL). +// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. +// All other rights reserved. + +using System.Collections.Specialized; +using System.Diagnostics; +using Avalonia; using Avalonia.Controls; using Avalonia.LogicalTree; +using Avalonia.Media; +using Avalonia.Utilities; namespace AtomUI.Controls.Cell; public sealed class DataGridCellsPresenter : Panel, IChildIndexProvider { + internal DataGrid? OwningGrid => OwningRow?.OwningGrid; + internal DataGridRow? OwningRow { get; set; } + + event EventHandler? IChildIndexProvider.ChildIndexChanged + { + add => _childIndexChanged += value; + remove => _childIndexChanged -= value; + } + + private double _fillerLeftEdge; + private EventHandler? _childIndexChanged; + + // The desired height needs to be cached due to column virtualization; otherwise, the cells + // would grow and shrink as the DataGrid scrolls horizontally + private double _desiredHeight; + + int IChildIndexProvider.GetChildIndex(ILogical child) + { + return child is DataGridCell cell + ? cell.OwningColumn?.DisplayIndex ?? -1 + : throw new InvalidOperationException("Invalid cell type"); + } + + bool IChildIndexProvider.TryGetTotalCount(out int count) + { + count = Children.Count - 1; // Adjust for filler column + return true; + } + + /// + /// Arranges the content of the . + /// + /// + /// The actual size used by the . + /// + /// + /// The final area within the parent that this element should use to arrange itself and its children. + /// + protected override Size ArrangeOverride(Size finalSize) + { + if (OwningGrid == null) + { + return base.ArrangeOverride(finalSize); + } + + Debug.Assert(OwningRow != null); + + if (OwningGrid.AutoSizingColumns) + { + // When we initially load an auto-column, we have to wait for all the rows to be measured + // before we know its final desired size. We need to trigger a new round of measures now + // that the final sizes have been calculated. + OwningGrid.AutoSizingColumns = false; + return base.ArrangeOverride(finalSize); + } + + double frozenLeftEdge = 0; + double scrollingLeftEdge = -OwningGrid.HorizontalOffset; + + double cellLeftEdge; + foreach (DataGridColumn column in OwningGrid.ColumnsInternal.GetVisibleColumns()) + { + DataGridCell cell = OwningRow.Cells[column.Index]; + Debug.Assert(cell.OwningColumn == column); + Debug.Assert(column.IsVisible); + + if (column.IsFrozen) + { + cellLeftEdge = frozenLeftEdge; + // This can happen before or after clipping because frozen cells aren't clipped + frozenLeftEdge += column.ActualWidth; + } + else + { + cellLeftEdge = scrollingLeftEdge; + } + if (cell.IsVisible) + { + cell.Arrange(new Rect(cellLeftEdge, 0, column.LayoutRoundedWidth, finalSize.Height)); + EnsureCellClip(cell, column.ActualWidth, finalSize.Height, frozenLeftEdge, scrollingLeftEdge); + } + scrollingLeftEdge += column.ActualWidth; + column.IsInitialDesiredWidthDetermined = true; + } + + _fillerLeftEdge = scrollingLeftEdge; + Debug.Assert(OwningGrid.ColumnsInternal.FillerColumn != null); + OwningRow.FillerCell.Arrange(new Rect(_fillerLeftEdge, 0, OwningGrid.ColumnsInternal.FillerColumn.FillerWidth, finalSize.Height)); + + return finalSize; + } + + private static void EnsureCellClip(DataGridCell cell, double width, double height, double frozenLeftEdge, double cellLeftEdge) + { + // Clip the cell only if it's scrolled under frozen columns. Unfortunately, we need to clip in this case + // because cells could be transparent + if (cell.OwningColumn != null && !cell.OwningColumn.IsFrozen && frozenLeftEdge > cellLeftEdge) + { + RectangleGeometry rg = new RectangleGeometry(); + double xClip = Math.Round(Math.Min(width, frozenLeftEdge - cellLeftEdge)); + rg.Rect = new Rect(xClip, 0, Math.Max(0, width - xClip), height); + cell.Clip = rg; + } + else + { + cell.Clip = null; + } + } + + protected override void ChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + base.ChildrenChanged(sender, e); + + InvalidateChildIndex(); + } + + private static void EnsureCellDisplay(DataGridCell cell, bool displayColumn) + { + if (cell.IsCurrent) + { + if (displayColumn) + { + cell.IsVisible = true; + cell.Clip = null; + } + else + { + // Clip + RectangleGeometry rg = new RectangleGeometry(); + rg.Rect = default; + cell.Clip = rg; + } + } + else + { + cell.IsVisible = displayColumn; + } + } + + internal void EnsureFillerVisibility() + { + Debug.Assert(OwningGrid != null); + Debug.Assert(OwningRow != null); + DataGridFillerColumn? fillerColumn = OwningGrid.ColumnsInternal.FillerColumn; + Debug.Assert(fillerColumn != null); + bool newVisibility = fillerColumn.IsActive; + if (OwningRow.FillerCell.IsVisible != newVisibility) + { + OwningRow.FillerCell.IsVisible = newVisibility; + if (newVisibility) + { + OwningRow.FillerCell.Arrange(new Rect(_fillerLeftEdge, 0, fillerColumn.FillerWidth, Bounds.Height)); + } + } + + // This must be done after the Filler visibility is determined. This also must be done + // regardless of whether or not the filler visibility actually changed values because + // we could scroll in a cell that didn't have EnsureGridLine called yet + DataGridColumn? lastVisibleColumn = OwningGrid.ColumnsInternal.LastVisibleColumn; + if (lastVisibleColumn != null) + { + DataGridCell cell = OwningRow.Cells[lastVisibleColumn.Index]; + cell.EnsureGridLine(lastVisibleColumn); + } + } + + /// + /// Measures the children of a to + /// prepare for arranging them during the pass. + /// + /// + /// The available size that this element can give to child elements. Indicates an upper limit that child elements should not exceed. + /// + /// + /// The size that the determines it needs during layout, based on its calculations of child object allocated sizes. + /// + protected override Size MeasureOverride(Size availableSize) + { + if (OwningGrid == null || OwningRow == null) + { + return base.MeasureOverride(availableSize); + } + + bool autoSizeHeight; + double measureHeight; + if (double.IsNaN(OwningGrid.RowHeight)) + { + // No explicit height values were set so we can autosize + autoSizeHeight = true; + // We need to invalidate desired height in order to grow or shrink as needed + InvalidateDesiredHeight(); + measureHeight = double.PositiveInfinity; + } + else + { + _desiredHeight = OwningGrid.RowHeight; + measureHeight = _desiredHeight; + autoSizeHeight = false; + } + + double frozenLeftEdge = 0; + double totalDisplayWidth = 0; + double scrollingLeftEdge = -OwningGrid.HorizontalOffset; + OwningGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth(); + DataGridColumn? lastVisibleColumn = OwningGrid.ColumnsInternal.LastVisibleColumn; + foreach (DataGridColumn column in OwningGrid.ColumnsInternal.GetVisibleColumns()) + { + DataGridCell cell = OwningRow.Cells[column.Index]; + // Measure the entire first row to make the horizontal scrollbar more accurate + bool shouldDisplayCell = ShouldDisplayCell(column, frozenLeftEdge, scrollingLeftEdge) || OwningRow.Index == 0; + EnsureCellDisplay(cell, shouldDisplayCell); + if (shouldDisplayCell) + { + DataGridLength columnWidth = column.Width; + bool autoGrowWidth = columnWidth.IsSizeToCells || columnWidth.IsAuto; + if (column != lastVisibleColumn) + { + cell.EnsureGridLine(lastVisibleColumn); + } + + // If we're not using star sizing or the current column can't be resized, + // then just set the display width according to the column's desired width + if (!OwningGrid.UsesStarSizing || (!column.ActualCanUserResize && !column.Width.IsStar)) + { + // In the edge-case where we're given infinite width and we have star columns, the + // star columns grow to their predefined limit of 10,000 (or their MaxWidth) + double newDisplayWidth = column.Width.IsStar ? + Math.Min(column.ActualMaxWidth, DataGrid.MaximumStarColumnWidth) : + Math.Max(column.ActualMinWidth, Math.Min(column.ActualMaxWidth, column.Width.DesiredValue)); + column.SetWidthDisplayValue(newDisplayWidth); + } + + // If we're auto-growing the column based on the cell content, we want to measure it at its maximum value + if (autoGrowWidth) + { + cell.Measure(new Size(column.ActualMaxWidth, measureHeight)); + OwningGrid.AutoSizeColumn(column, cell.DesiredSize.Width); + column.ComputeLayoutRoundedWidth(totalDisplayWidth); + } + else if (!OwningGrid.UsesStarSizing) + { + column.ComputeLayoutRoundedWidth(scrollingLeftEdge); + cell.Measure(new Size(column.LayoutRoundedWidth, measureHeight)); + } + + // We need to track the largest height in order to auto-size + if (autoSizeHeight) + { + _desiredHeight = Math.Max(_desiredHeight, cell.DesiredSize.Height); + } + } + + if (column.IsFrozen) + { + frozenLeftEdge += column.ActualWidth; + } + scrollingLeftEdge += column.ActualWidth; + totalDisplayWidth += column.ActualWidth; + } + + // If we're using star sizing (and we're not waiting for an auto-column to finish growing) + // then we will resize all the columns to fit the available space. + if (OwningGrid.UsesStarSizing && !OwningGrid.AutoSizingColumns) + { + double adjustment = OwningGrid.CellsWidth - totalDisplayWidth; + totalDisplayWidth += adjustment - OwningGrid.AdjustColumnWidths(0, adjustment, false); + + // Since we didn't know the final widths of the columns until we resized, + // we waited until now to measure each cell + double leftEdge = 0; + if (autoSizeHeight) + _desiredHeight = 0; + + foreach (DataGridColumn column in OwningGrid.ColumnsInternal.GetVisibleColumns()) + { + DataGridCell cell = OwningRow.Cells[column.Index]; + column.ComputeLayoutRoundedWidth(leftEdge); + cell.Measure(new Size(column.LayoutRoundedWidth, measureHeight)); + if (autoSizeHeight) + { + _desiredHeight = Math.Max(_desiredHeight, cell.DesiredSize.Height); + } + leftEdge += column.ActualWidth; + } + } + + // Measure FillerCell, we're doing it unconditionally here because we don't know if we'll need the filler + // column and we don't want to cause another Measure if we do + OwningRow.FillerCell.Measure(new Size(double.PositiveInfinity, _desiredHeight)); + + OwningGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth(); + return new Size(OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth, _desiredHeight); + } + + internal void Recycle() + { + // Clear out the cached desired height so it is not reused for other rows + _desiredHeight = 0; + } + + internal void InvalidateDesiredHeight() + { + _desiredHeight = 0; + } + + internal void InvalidateChildIndex() + { + _childIndexChanged?.Invoke(this, ChildIndexChangedEventArgs.ChildIndexesReset); + } + + private bool ShouldDisplayCell(DataGridColumn column, double frozenLeftEdge, double scrollingLeftEdge) + { + if (!column.IsVisible) + { + return false; + } + Debug.Assert(OwningGrid != null); + scrollingLeftEdge += OwningGrid.HorizontalAdjustment; + double leftEdge = column.IsFrozen ? frozenLeftEdge : scrollingLeftEdge; + double rightEdge = leftEdge + column.ActualWidth; + return + MathUtilities.GreaterThan(rightEdge, 0) && + MathUtilities.LessThanOrClose(leftEdge, OwningGrid.CellsWidth) && + MathUtilities.GreaterThan(rightEdge, frozenLeftEdge); // scrolling column covered up by frozen column(s) + } } \ No newline at end of file diff --git a/src/AtomUI.Controls.DataGrid/DataGrid.Cells.cs b/src/AtomUI.Controls.DataGrid/DataGrid.Cells.cs new file mode 100644 index 000000000..89797fe03 --- /dev/null +++ b/src/AtomUI.Controls.DataGrid/DataGrid.Cells.cs @@ -0,0 +1,57 @@ +using System.Diagnostics; +using Avalonia.Controls; + +namespace AtomUI.Controls; + +public partial class DataGrid +{ + #region 内部属性定义 + + // Width currently available for cells this value is smaller. This width is reduced by the existence of RowHeaders + // or a vertical scrollbar. Layout is asynchronous so changes to the RowHeaders or the vertical scrollbar are + // not reflected immediately + internal double CellsWidth + { + get + { + double rowsWidth = double.PositiveInfinity; + if (RowsPresenterAvailableSize.HasValue) + { + rowsWidth = Math.Max(0, RowsPresenterAvailableSize.Value.Width - ActualRowHeaderWidth); + } + return double.IsPositiveInfinity(rowsWidth) ? ColumnsInternal.VisibleEdgedColumnsWidth : rowsWidth; + } + } + + internal int CurrentSlot + { + get => CurrentCellCoordinates.Slot; + private set => CurrentCellCoordinates.Slot = value; + } + + internal int SlotCount { get; private set; } + internal double CellsEstimatedHeight => RowsPresenterAvailableSize?.Height ?? 0; + + private bool IsHorizontalScrollBarOverCells => _columnHeadersPresenter != null && Grid.GetColumnSpan(_columnHeadersPresenter) == 2; + + private bool IsVerticalScrollBarOverCells => _rowsPresenter != null && Grid.GetRowSpan(_rowsPresenter) == 2; + + internal int VisibleSlotCount { get; set; } + + internal double AvailableSlotElementRoom { get; set; } + + #endregion + + internal static DataGridCell? GetOwningCell(Control element) + { + Debug.Assert(element != null); + DataGridCell? cell = element as DataGridCell; + Control? target = element; + while (target != null && cell == null) + { + target = target.Parent as Control; + cell = target as DataGridCell; + } + return cell; + } +} \ No newline at end of file diff --git a/src/AtomUI.Controls.DataGrid/DataGrid.cs b/src/AtomUI.Controls.DataGrid/DataGrid.cs index 3bd3544ee..36f266f1d 100644 --- a/src/AtomUI.Controls.DataGrid/DataGrid.cs +++ b/src/AtomUI.Controls.DataGrid/DataGrid.cs @@ -1129,7 +1129,7 @@ public partial class DataGrid : TemplatedControl /// /// Raises the BeginningEdit event. /// - protected virtual void OnBeginningEdit(DataGridBeginningEditEventArgs e) + protected virtual void NotifyBeginningEdit(DataGridBeginningEditEventArgs e) { BeginningEdit?.Invoke(this, e); } @@ -1137,7 +1137,7 @@ public partial class DataGrid : TemplatedControl /// /// Raises the CellEditEnded event. /// - protected virtual void OnCellEditEnded(DataGridCellEditEndedEventArgs e) + protected virtual void NotifyCellEditEnded(DataGridCellEditEndedEventArgs e) { CellEditEnded?.Invoke(this, e); } @@ -1145,7 +1145,7 @@ public partial class DataGrid : TemplatedControl /// /// Raises the CellEditEnding event. /// - protected virtual void OnCellEditEnding(DataGridCellEditEndingEventArgs e) + protected virtual void NotifyCellEditEnding(DataGridCellEditEndingEventArgs e) { CellEditEnding?.Invoke(this, e); } @@ -1153,7 +1153,7 @@ public partial class DataGrid : TemplatedControl /// /// Raises the CellPointerPressed event. /// - internal virtual void OnCellPointerPressed(DataGridCellPointerPressedEventArgs e) + internal virtual void NotifyCellPointerPressed(DataGridCellPointerPressedEventArgs e) { CellPointerPressed?.Invoke(this, e); } @@ -2262,7 +2262,7 @@ public partial class DataGrid : TemplatedControl // Raise the BeginningEdit event DataGridCell dataGridCell = dataGridRow.Cells[CurrentColumnIndex]; DataGridBeginningEditEventArgs e = new DataGridBeginningEditEventArgs(CurrentColumn, dataGridRow, editingEventArgs); - OnBeginningEdit(e); + NotifyBeginningEdit(e); if (e.Cancel || currentRowIndex != CurrentSlot || currentColumnIndex != CurrentColumnIndex @@ -2951,7 +2951,7 @@ public partial class DataGrid : TemplatedControl { Debug.Assert(CurrentColumn != null); DataGridCellEditEndingEventArgs e = new DataGridCellEditEndingEventArgs(CurrentColumn, editingRow, editingElement, editAction); - OnCellEditEnding(e); + NotifyCellEditEnding(e); if (e.Cancel) { // CellEditEnding has been cancelled @@ -3066,7 +3066,7 @@ public partial class DataGrid : TemplatedControl // We're done, so raise the CellEditEnded event if (raiseEvents) { - OnCellEditEnded(new DataGridCellEditEndedEventArgs(CurrentColumn, editingRow, editAction)); + NotifyCellEditEnded(new DataGridCellEditEndedEventArgs(CurrentColumn, editingRow, editAction)); } // There's a chance that somebody reopened this cell for edit within the CellEditEnded handler, diff --git a/src/AtomUI.Controls.DataGrid/Row/DataGridRowGroupInfo.cs b/src/AtomUI.Controls.DataGrid/Row/DataGridRowGroupInfo.cs index ee2165e11..93d9a1bc3 100644 --- a/src/AtomUI.Controls.DataGrid/Row/DataGridRowGroupInfo.cs +++ b/src/AtomUI.Controls.DataGrid/Row/DataGridRowGroupInfo.cs @@ -5,7 +5,7 @@ namespace AtomUI.Controls; internal class DataGridRowGroupInfo { public DataGridRowGroupInfo( - DataGridCollectionViewGroup collectionViewGroup, + DataGridCollectionViewGroup? collectionViewGroup, bool isVisible, int level, int slot, @@ -18,7 +18,7 @@ internal class DataGridRowGroupInfo LastSubItemSlot = lastSubItemSlot; } - public DataGridCollectionViewGroup CollectionViewGroup + public DataGridCollectionViewGroup? CollectionViewGroup { get; private set; diff --git a/src/AtomUI.Controls.DataGrid/Theme/DataGridCellTheme.cs b/src/AtomUI.Controls.DataGrid/Theme/DataGridCellTheme.cs index 102874035..fd0ddfd15 100644 --- a/src/AtomUI.Controls.DataGrid/Theme/DataGridCellTheme.cs +++ b/src/AtomUI.Controls.DataGrid/Theme/DataGridCellTheme.cs @@ -6,6 +6,8 @@ namespace AtomUI.Controls; [ControlThemeProvider] internal class DataGridCellTheme : BaseControlTheme { + public const string RightGridLinePart = "PART_RightGridLine"; + public DataGridCellTheme() : base(typeof(DataGridCell)) {