mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-29 07:16:33 +08:00
Add DataGridCell
This commit is contained in:
@@ -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<DataGridCell, bool> IsValidProperty =
|
||||
AvaloniaProperty.RegisterDirect<DataGridCell, bool>(
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Builds the visual tree for the cell control when a new template is applied.
|
||||
/// </summary>
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
UpdatePseudoClasses();
|
||||
_rightGridLine = e.NameScope.Find<Rectangle>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<ChildIndexChangedEventArgs>? IChildIndexProvider.ChildIndexChanged
|
||||
{
|
||||
add => _childIndexChanged += value;
|
||||
remove => _childIndexChanged -= value;
|
||||
}
|
||||
|
||||
private double _fillerLeftEdge;
|
||||
private EventHandler<ChildIndexChangedEventArgs>? _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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arranges the content of the <see cref="T:Avalonia.Controls.Primitives.DataGridCellsPresenter" />.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The actual size used by the <see cref="T:Avalonia.Controls.Primitives.DataGridCellsPresenter" />.
|
||||
/// </returns>
|
||||
/// <param name="finalSize">
|
||||
/// The final area within the parent that this element should use to arrange itself and its children.
|
||||
/// </param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Measures the children of a <see cref="T:Avalonia.Controls.Primitives.DataGridCellsPresenter" /> to
|
||||
/// prepare for arranging them during the <see cref="M:System.Windows.FrameworkElement.ArrangeOverride(System.Windows.Size)" /> pass.
|
||||
/// </summary>
|
||||
/// <param name="availableSize">
|
||||
/// The available size that this element can give to child elements. Indicates an upper limit that child elements should not exceed.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The size that the <see cref="T:Avalonia.Controls.Primitives.DataGridCellsPresenter" /> determines it needs during layout, based on its calculations of child object allocated sizes.
|
||||
/// </returns>
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1129,7 +1129,7 @@ public partial class DataGrid : TemplatedControl
|
||||
/// <summary>
|
||||
/// Raises the BeginningEdit event.
|
||||
/// </summary>
|
||||
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
|
||||
/// <summary>
|
||||
/// Raises the CellEditEnded event.
|
||||
/// </summary>
|
||||
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
|
||||
/// <summary>
|
||||
/// Raises the CellEditEnding event.
|
||||
/// </summary>
|
||||
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
|
||||
/// <summary>
|
||||
/// Raises the CellPointerPressed event.
|
||||
/// </summary>
|
||||
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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace AtomUI.Controls;
|
||||
[ControlThemeProvider]
|
||||
internal class DataGridCellTheme : BaseControlTheme
|
||||
{
|
||||
public const string RightGridLinePart = "PART_RightGridLine";
|
||||
|
||||
public DataGridCellTheme()
|
||||
: base(typeof(DataGridCell))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user