Add DataGridRowHeader

This commit is contained in:
CHINBOY
2025-05-29 00:12:29 +08:00
parent 63320d11e4
commit da976fb80d
11 changed files with 202 additions and 236 deletions
@@ -2,7 +2,7 @@ using AtomUI.Controls.Utils;
using AtomUI.Reactive;
using Avalonia.Data;
namespace AtomUI.Controls.Cell;
namespace AtomUI.Controls;
internal class CellEditBinding : ICellEditBinding
{
@@ -11,7 +11,7 @@ using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Utilities;
namespace AtomUI.Controls.Cell;
namespace AtomUI.Controls;
public sealed class DataGridCellsPresenter : Panel, IChildIndexProvider
{
@@ -1,4 +1,4 @@
namespace AtomUI.Controls.Cell;
namespace AtomUI.Controls;
public interface ICellEditBinding
{
@@ -132,6 +132,45 @@ public partial class DataGrid
}
}
internal int? MouseOverRowIndex
{
get => _mouseOverRowIndex;
set
{
if (_mouseOverRowIndex != value)
{
DataGridRow? oldMouseOverRow = null;
if (_mouseOverRowIndex.HasValue)
{
int oldSlot = SlotFromRowIndex(_mouseOverRowIndex.Value);
if (IsSlotVisible(oldSlot))
{
oldMouseOverRow = DisplayData.GetDisplayedElement(oldSlot) as DataGridRow;
}
}
_mouseOverRowIndex = value;
// State for the old row needs to be applied after setting the new value
if (oldMouseOverRow != null)
{
oldMouseOverRow.ApplyState();
}
if (_mouseOverRowIndex.HasValue)
{
int newSlot = SlotFromRowIndex(_mouseOverRowIndex.Value);
if (IsSlotVisible(newSlot))
{
DataGridRow? newMouseOverRow = DisplayData.GetDisplayedElement(newSlot) as DataGridRow;
Debug.Assert(newMouseOverRow != null);
newMouseOverRow.ApplyState();
}
}
}
}
}
internal ScrollBar? VerticalScrollBar => _vScrollBar;
#endregion
@@ -146,7 +185,7 @@ public partial class DataGrid
/// </remarks>
private const int DefaultColumnDisplayOrder = 10000;
private const double HorizontalGridLinesThickness = 1;
internal const double HorizontalGridLinesThickness = 1;
private const double MinimumRowHeaderWidth = 4;
private const double MinimumColumnHeaderHeight = 4;
internal const double MaximumStarColumnWidth = 10000;
+3 -3
View File
@@ -7,7 +7,6 @@ using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using AtomUI.Controls.Cell;
using AtomUI.Controls.Data;
using AtomUI.Controls.Utils;
using AtomUI.Utils;
@@ -1945,6 +1944,7 @@ public partial class DataGrid : TemplatedControl
_noCurrentCellChangeCount++;
try
{
Debug.Assert(ColumnsInternal.RowGroupSpacerColumn != null);
if (ColumnsInternal.RowGroupSpacerColumn.IsRepresented &&
columnIndex == ColumnsInternal.RowGroupSpacerColumn.Index)
{
@@ -1993,7 +1993,7 @@ public partial class DataGrid : TemplatedControl
// The DataGrid's CurrentItem is already up-to-date, so we don't need to do anything
return;
}
Debug.Assert(ColumnsInternal.RowGroupSpacerColumn != null);
int columnIndex = CurrentColumnIndex;
if (columnIndex == -1)
{
@@ -2124,7 +2124,7 @@ public partial class DataGrid : TemplatedControl
}
}
internal void OnRowDetailsChanged()
internal void NotifyRowDetailsChanged()
{
if (!_scrollingByHeight)
{
@@ -1,5 +1,5 @@
using System.Diagnostics;
using Avalonia;
using Avalonia.Automation.Peers;
using Avalonia.Controls;
using Avalonia.Media;
@@ -22,12 +22,9 @@ public sealed class DataGridDetailsPresenter : Panel
set => SetValue(ContentHeightProperty, value);
}
internal DataGridRow? OwningRow
{
get;
set;
}
// private DataGrid? OwningGrid => OwningRow?.OwningGrid;
internal DataGridRow? OwningRow { get; set; }
private DataGrid? OwningGrid => OwningRow?.OwningGrid;
public DataGridDetailsPresenter()
{
@@ -50,46 +47,47 @@ public sealed class DataGridDetailsPresenter : Panel
/// </param>
protected override Size ArrangeOverride(Size finalSize)
{
// if (OwningGrid == null)
// {
// return base.ArrangeOverride(finalSize);
// }
// double rowGroupSpacerWidth = OwningGrid.ColumnsInternal.RowGroupSpacerColumn.Width.Value;
// double leftEdge = rowGroupSpacerWidth;
// double xClip = OwningGrid.AreRowGroupHeadersFrozen ? rowGroupSpacerWidth : 0;
// double width;
// if (OwningGrid.AreRowDetailsFrozen)
// {
// leftEdge += OwningGrid.HorizontalOffset;
// width = OwningGrid.CellsWidth;
// }
// else
// {
// xClip += OwningGrid.HorizontalOffset;
// width = Math.Max(OwningGrid.CellsWidth, OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth);
// }
// // Details should not extend through the indented area
// width -= rowGroupSpacerWidth;
// double height = Math.Max(0, double.IsNaN(ContentHeight) ? 0 : ContentHeight);
//
// foreach (Control child in Children)
// {
// child.Arrange(new Rect(leftEdge, 0, width, height));
// }
//
// if (OwningGrid.AreRowDetailsFrozen)
// {
// // Frozen Details should not be clipped, similar to frozen cells
// Clip = null;
// }
// else
// {
// // Clip so Details doesn't obstruct elements to the left (the RowHeader by default) as we scroll to the right
// Clip = new RectangleGeometry
// {
// Rect = new Rect(xClip, 0, Math.Max(0, width - xClip + rowGroupSpacerWidth), height)
// };
// }
if (OwningGrid == null)
{
return base.ArrangeOverride(finalSize);
}
Debug.Assert(OwningGrid.ColumnsInternal.RowGroupSpacerColumn != null);
double rowGroupSpacerWidth = OwningGrid.ColumnsInternal.RowGroupSpacerColumn.Width.Value;
double leftEdge = rowGroupSpacerWidth;
double xClip = OwningGrid.AreRowGroupHeadersFrozen ? rowGroupSpacerWidth : 0;
double width;
if (OwningGrid.AreRowDetailsFrozen)
{
leftEdge += OwningGrid.HorizontalOffset;
width = OwningGrid.CellsWidth;
}
else
{
xClip += OwningGrid.HorizontalOffset;
width = Math.Max(OwningGrid.CellsWidth, OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth);
}
// Details should not extend through the indented area
width -= rowGroupSpacerWidth;
double height = Math.Max(0, double.IsNaN(ContentHeight) ? 0 : ContentHeight);
foreach (Control child in Children)
{
child.Arrange(new Rect(leftEdge, 0, width, height));
}
if (OwningGrid.AreRowDetailsFrozen)
{
// Frozen Details should not be clipped, similar to frozen cells
Clip = null;
}
else
{
// Clip so Details doesn't obstruct elements to the left (the RowHeader by default) as we scroll to the right
Clip = new RectangleGeometry
{
Rect = new Rect(xClip, 0, Math.Max(0, width - xClip + rowGroupSpacerWidth), height)
};
}
return finalSize;
}
@@ -106,25 +104,25 @@ public sealed class DataGridDetailsPresenter : Panel
/// </returns>
protected override Size MeasureOverride(Size availableSize)
{
return default;
// if (OwningGrid == null || Children.Count == 0)
// {
// return default;
// }
if (OwningGrid == null || Children.Count == 0)
{
return default;
}
Debug.Assert(OwningGrid.ColumnsInternal.RowGroupSpacerColumn != null);
// double desiredWidth = OwningGrid.AreRowDetailsFrozen ?
// OwningGrid.CellsWidth :
// Math.Max(OwningGrid.CellsWidth, OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth);
//
// desiredWidth -= OwningGrid.ColumnsInternal.RowGroupSpacerColumn.Width.Value;
//
// foreach (Control child in Children)
// {
// child.Measure(new Size(desiredWidth, double.PositiveInfinity));
// }
//
// double desiredHeight = Math.Max(0, double.IsNaN(ContentHeight) ? 0 : ContentHeight);
//
// return new Size(desiredWidth, desiredHeight);
double desiredWidth = OwningGrid.AreRowDetailsFrozen ?
OwningGrid.CellsWidth :
Math.Max(OwningGrid.CellsWidth, OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth);
desiredWidth -= OwningGrid.ColumnsInternal.RowGroupSpacerColumn.Width.Value;
foreach (Control child in Children)
{
child.Measure(new Size(desiredWidth, double.PositiveInfinity));
}
double desiredHeight = Math.Max(0, double.IsNaN(ContentHeight) ? 0 : ContentHeight);
return new Size(desiredWidth, desiredHeight);
}
}
@@ -3,15 +3,18 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System.Diagnostics;
using System.Drawing;
using System.Reactive.Disposables;
using AtomUI.Controls.Cell;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Utilities;
using System.Diagnostics;
using System.Reactive.Disposables;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Styling;
namespace AtomUI.Controls;
@@ -29,7 +32,7 @@ public partial class DataGridRow
// Returns the actual template that should be sued for Details: either explicity set on this row
// or inherited from the DataGrid
private IDataTemplate ActualDetailsTemplate
private IDataTemplate? ActualDetailsTemplate
{
get
{
@@ -55,6 +58,7 @@ public partial class DataGridRow
{
get
{
Debug.Assert(OwningGrid != null);
if (_fillerCell == null)
{
_fillerCell = new DataGridCell
@@ -105,11 +109,7 @@ public partial class DataGridRow
}
}
internal bool IsRecycled
{
get;
private set;
}
internal bool IsRecycled { get; private set; }
internal bool IsRecyclable
{
@@ -125,12 +125,10 @@ public partial class DataGridRow
internal int? MouseOverColumnIndex
{
get
{
return _mouseOverColumnIndex;
}
get => _mouseOverColumnIndex;
set
{
Debug.Assert(OwningGrid != null);
if (_mouseOverColumnIndex != value)
{
DataGridCell? oldMouseOverCell = null;
@@ -157,11 +155,7 @@ public partial class DataGridRow
}
}
internal Panel? RootElement
{
get;
private set;
}
internal Panel? RootElement { get; private set; }
// Height that the row will eventually end up at after a possible details animation has completed
internal double TargetHeight
@@ -181,17 +175,6 @@ public partial class DataGridRow
return DesiredSize.Height;
}
}
// Returns the actual template that should be sued for Details: either explicity set on this row
// or inherited from the DataGrid
private IDataTemplate ActualDetailsTemplate
{
get
{
Debug.Assert(OwningGrid != null);
return DetailsTemplate ?? OwningGrid.RowDetailsTemplate;
}
}
private bool ActualDetailsVisibility
{
@@ -264,7 +247,7 @@ public partial class DataGridRow
if (!_areHandlersSuspended && OwningGrid != null)
{
IDataTemplate actualDetailsTemplate(IDataTemplate? template) => (template ?? OwningGrid.RowDetailsTemplate);
IDataTemplate? actualDetailsTemplate(IDataTemplate? template) => (template ?? OwningGrid.RowDetailsTemplate);
// We don't always want to apply the new Template because they might have set the same one
// we inherited from the DataGrid
@@ -277,9 +260,10 @@ public partial class DataGridRow
internal void ApplyDetailsTemplate(bool initializeDetailsPreferredHeight)
{
Debug.Assert(OwningGrid != null);
if (_detailsElement != null && AreDetailsVisible)
{
IDataTemplate oldDetailsTemplate = _appliedDetailsTemplate;
IDataTemplate? oldDetailsTemplate = _appliedDetailsTemplate;
if (ActualDetailsTemplate != null && ActualDetailsTemplate != _appliedDetailsTemplate)
{
if (_detailsContent != null)
@@ -288,7 +272,7 @@ public partial class DataGridRow
_detailsContentSizeSubscription = null;
if (_detailsLoaded)
{
OwningGrid.OnUnloadingRowDetails(this, _detailsContent);
OwningGrid.NotifyUnloadingRowDetails(this, _detailsContent);
_detailsLoaded = false;
}
}
@@ -299,14 +283,14 @@ public partial class DataGridRow
if (_detailsContent != null)
{
if (_detailsContent is Layout.Layoutable layoutableContent)
if (_detailsContent is Layoutable layoutableContent)
{
layoutableContent.LayoutUpdated += HandleLayoutUpdated;
_detailsContentSizeSubscription = new CompositeDisposable(2)
{
Disposable.Create(() => layoutableContent.LayoutUpdated -= HandleLayoutUpdated),
_detailsContent.GetObservable(MarginProperty).Subscribe(HandleMarginChanged)
_detailsContent.GetObservable(MarginProperty).Subscribe(NotifyMarginChanged)
};
@@ -315,7 +299,7 @@ public partial class DataGridRow
{
_detailsContentSizeSubscription =
_detailsContent.GetObservable(MarginProperty)
.Subscribe(HandleMarginChanged);
.Subscribe(NotifyMarginChanged);
}
@@ -327,7 +311,7 @@ public partial class DataGridRow
{
_detailsLoaded = true;
_detailsContent.DataContext = DataContext;
OwningGrid.OnLoadingRowDetails(this, _detailsContent);
OwningGrid.NotifyLoadingRowDetails(this, _detailsContent);
}
if (initializeDetailsPreferredHeight && double.IsNaN(_detailsDesiredHeight) &&
_appliedDetailsTemplate != null && _detailsElement.Children.Count > 0)
@@ -356,8 +340,8 @@ public partial class DataGridRow
throw DataGridError.DataGridRow.InvalidRowIndexCannotCompleteOperation();
}
var newValue = (bool)e.NewValue;
OwningGrid.OnRowDetailsVisibilityPropertyChanged(Index, newValue);
var newValue = (bool)(e.NewValue ?? false);
OwningGrid.NotifyRowDetailsVisibilityPropertyChanged(Index, newValue);
SetDetailsVisibilityInternal(newValue, raiseNotification: true, animate: true);
}
}
@@ -385,6 +369,7 @@ public partial class DataGridRow
internal void ApplyHeaderStatus()
{
Debug.Assert(OwningGrid != null);
if (_headerElement != null && OwningGrid.AreRowHeadersVisible)
{
_headerElement.UpdatePseudoClasses();
@@ -467,7 +452,7 @@ public partial class DataGridRow
}
}
internal void EnsureHeaderStyleAndVisibility(Styling.Style previousStyle)
internal void EnsureHeaderStyleAndVisibility(Style? previousStyle)
{
if (_headerElement != null && OwningGrid != null)
{
@@ -505,43 +490,16 @@ public partial class DataGridRow
_bottomGridLine = null;
}
private void HandleCellAdded(object sender, DataGridCellEventArgs e)
{
_cellsElement?.Children.Add(e.Cell);
}
private void HandleCellRemoved(object sender, DataGridCellEventArgs e)
{
_cellsElement?.Children.Remove(e.Cell);
}
private void HandlePointerPressed(PointerPressedEventArgs e)
{
if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
return;
}
if (OwningGrid != null)
{
OwningGrid.IsDoubleClickRecordsClickOnCall(this);
}
}
private void HandleRowDetailsChanged()
{
OwningGrid?.OnRowDetailsChanged();
}
private void UnloadDetailsTemplate(bool recycle)
{
Debug.Assert(OwningGrid != null);
if (_detailsElement != null)
{
if (_detailsContent != null)
{
if (_detailsLoaded)
{
OwningGrid.OnUnloadingRowDetails(this, _detailsContent);
OwningGrid.NotifyUnloadingRowDetails(this, _detailsContent);
}
_detailsContent.DataContext = null;
if (!recycle)
@@ -612,17 +570,18 @@ public partial class DataGridRow
double? _previousDetailsHeight = null;
//TODO Animation
private void HandleHeightChanged(double newValue)
private void NotifyHeightChanged(double newValue)
{
if (_previousDetailsHeight.HasValue)
{
var oldValue = _previousDetailsHeight.Value;
_previousDetailsHeight = newValue;
if (newValue != oldValue && newValue != _detailsDesiredHeight)
if (!MathUtils.AreClose(newValue, oldValue) && !MathUtils.AreClose(newValue, _detailsDesiredHeight))
{
if (AreDetailsVisible && _appliedDetailsTemplate != null)
{
Debug.Assert(_detailsElement != null);
// Update the new desired height for RowDetails
_detailsDesiredHeight = newValue;
@@ -630,7 +589,7 @@ public partial class DataGridRow
// Calling this when details are not visible invalidates during layout when we have no work
// to do. In certain scenarios, this could cause a layout cycle
OnRowDetailsChanged();
NotifyRowDetailsChanged();
}
}
}
@@ -639,26 +598,34 @@ public partial class DataGridRow
_previousDetailsHeight = newValue;
}
}
private void HandleSizeChanged(Rect newValue)
private void NotifyRowDetailsChanged()
{
HandleHeightChanged(newValue.Height);
OwningGrid?.NotifyRowDetailsChanged();
}
private void HandleMarginChanged(Thickness newValue)
private void NotifySizeChanged(Rect newValue)
{
NotifyHeightChanged(newValue.Height);
}
private void NotifyMarginChanged(Thickness newValue)
{
if (_detailsContent != null)
HandleSizeChanged(_detailsContent.Bounds.Inflate(newValue));
{
NotifySizeChanged(_detailsContent.Bounds.Inflate(newValue));
}
}
private void HandleLayoutUpdated(object sender, EventArgs e)
private void HandleLayoutUpdated(object? sender, EventArgs e)
{
if (_detailsContent != null)
{
var margin = _detailsContent.Margin;
var height = _detailsContent.DesiredSize.Height + margin.Top + margin.Bottom;
HandleHeightChanged(height);
NotifyHeightChanged(height);
}
}
@@ -707,80 +674,26 @@ public partial class DataGridRow
_detailsElement.ContentHeight = 0;
}
OnRowDetailsChanged();
NotifyRowDetailsChanged();
if (raiseNotification)
{
Debug.Assert(_detailsContent != null);
OwningGrid.OnRowDetailsVisibilityChanged(new DataGridRowDetailsEventArgs(this, _detailsContent));
}
}
}
internal void ApplyDetailsTemplate(bool initializeDetailsPreferredHeight)
private void SetValueNoCallback<T>(AvaloniaProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
{
if (_detailsElement != null && AreDetailsVisible)
_areHandlersSuspended = true;
try
{
IDataTemplate oldDetailsTemplate = _appliedDetailsTemplate;
if (ActualDetailsTemplate != null && ActualDetailsTemplate != _appliedDetailsTemplate)
{
if (_detailsContent != null)
{
_detailsContentSizeSubscription?.Dispose();
_detailsContentSizeSubscription = null;
if (_detailsLoaded)
{
OwningGrid.OnUnloadingRowDetails(this, _detailsContent);
_detailsLoaded = false;
}
}
_detailsElement.Children.Clear();
_detailsContent = ActualDetailsTemplate.Build(DataContext);
_appliedDetailsTemplate = ActualDetailsTemplate;
if (_detailsContent != null)
{
if (_detailsContent is Layout.Layoutable layoutableContent)
{
layoutableContent.LayoutUpdated += HandleLayoutUpdated;
_detailsContentSizeSubscription = new CompositeDisposable(2)
{
Disposable.Create(() => layoutableContent.LayoutUpdated -= HandleLayoutUpdated),
_detailsContent.GetObservable(MarginProperty).Subscribe(HandleMarginChanged)
};
}
else
{
_detailsContentSizeSubscription =
_detailsContent.GetObservable(MarginProperty)
.Subscribe(HandleMarginChanged);
}
_detailsElement.Children.Add(_detailsContent);
}
}
if (_detailsContent != null && !_detailsLoaded)
{
_detailsLoaded = true;
_detailsContent.DataContext = DataContext;
OwningGrid.OnLoadingRowDetails(this, _detailsContent);
}
if (initializeDetailsPreferredHeight && double.IsNaN(_detailsDesiredHeight) &&
_appliedDetailsTemplate != null && _detailsElement.Children.Count > 0)
{
EnsureDetailsDesiredHeight();
}
else if (oldDetailsTemplate == null)
{
_detailsDesiredHeight = double.NaN;
EnsureDetailsDesiredHeight();
_detailsElement.ContentHeight = _detailsDesiredHeight;
}
SetValue(property, value, priority);
}
finally
{
_areHandlersSuspended = false;
}
}
}
@@ -3,10 +3,13 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using AtomUI.Controls.Utils;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Automation;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Media;
@@ -162,7 +165,7 @@ public partial class DataGridRow : TemplatedControl
// If the DataGrid was scrolled horizontally after our last Arrange, we need to make sure
// the Cells and Details are Arranged again
if (_lastHorizontalOffset != OwningGrid.HorizontalOffset)
if (!MathUtils.AreClose(_lastHorizontalOffset, OwningGrid.HorizontalOffset))
{
_lastHorizontalOffset = OwningGrid.HorizontalOffset;
InvalidateHorizontalArrange();
@@ -240,7 +243,7 @@ public partial class DataGridRow : TemplatedControl
/// </summary>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
RootElement = e.NameScope.Find<Panel>(DATAGRIDROW_elementRoot);
RootElement = e.NameScope.Find<Panel>(DataGridRowTheme.FramePart);
if (RootElement != null)
{
ApplyState();
@@ -254,7 +257,7 @@ public partial class DataGridRow : TemplatedControl
updateVerticalScrollBar = true;
}
_cellsElement = e.NameScope.Find<DataGridCellsPresenter>(DATAGRIDROW_elementCells);
_cellsElement = e.NameScope.Find<DataGridCellsPresenter>(DataGridRowTheme.CellsPresenterPart);
if (_cellsElement != null)
{
_cellsElement.OwningRow = this;
@@ -269,7 +272,7 @@ public partial class DataGridRow : TemplatedControl
}
}
_detailsElement = e.NameScope.Find<DataGridDetailsPresenter>(DATAGRIDROW_elementDetails);
_detailsElement = e.NameScope.Find<DataGridDetailsPresenter>(DataGridRowTheme.DetailsPresenterPart);
if (_detailsElement != null && OwningGrid != null)
{
_detailsElement.OwningRow = this;
@@ -281,10 +284,10 @@ public partial class DataGridRow : TemplatedControl
}
}
_bottomGridLine = e.NameScope.Find<Rectangle>(DATAGRIDROW_elementBottomGridLine);
_bottomGridLine = e.NameScope.Find<Rectangle>(DataGridRowTheme.BottomGridLinePart);
EnsureGridLines();
_headerElement = e.NameScope.Find<DataGridRowHeader>(DATAGRIDROW_elementRowHeader);
_headerElement = e.NameScope.Find<DataGridRowHeader>(DataGridRowTheme.RowHeaderPart);
if (_headerElement != null)
{
_headerElement.Owner = this;
@@ -326,7 +329,11 @@ public partial class DataGridRow : TemplatedControl
{
if (columns[ci] is DataGridTemplateColumn column)
{
column.RefreshCellContent((Control)this.Cells[column.Index].Content, nameof(DataGridTemplateColumn.CellTemplate));
var content = (Control?)Cells[column.Index].Content;
if (content != null)
{
column.RefreshCellContent(content, nameof(DataGridTemplateColumn.CellTemplate));
}
}
}
}
@@ -28,8 +28,8 @@ public class DataGridRowGroupHeader : TemplatedControl
public static readonly StyledProperty<string> ItemCountFormatProperty =
AvaloniaProperty.Register<DataGridRowGroupHeader, string>(nameof(ItemCountFormat));
public static readonly StyledProperty<string> PropertyNameProperty =
AvaloniaProperty.Register<DataGridRowGroupHeader, string>(nameof(PropertyName));
public static readonly StyledProperty<string?> PropertyNameProperty =
AvaloniaProperty.Register<DataGridRowGroupHeader, string?>(nameof(PropertyName));
public static readonly StyledProperty<bool> IsPropertyNameVisibleProperty =
AvaloniaProperty.Register<DataGridRowGroupHeader, bool>(nameof(IsPropertyNameVisible));
@@ -61,7 +61,7 @@ public class DataGridRowGroupHeader : TemplatedControl
/// <summary>
/// Gets or sets the name of the property that this <see cref="T:Avalonia.Controls.DataGrid" /> row is bound to.
/// </summary>
public string PropertyName
public string? PropertyName
{
get => GetValue(PropertyNameProperty);
set => SetValue(PropertyNameProperty, value);
@@ -97,6 +97,7 @@ public class DataGridRowGroupHeader : TemplatedControl
get
{
Debug.Assert(OwningGrid != null);
Debug.Assert(RowGroupInfo != null);
return (RowGroupInfo.Slot == OwningGrid.CurrentSlot);
}
}
@@ -151,7 +152,7 @@ public class DataGridRowGroupHeader : TemplatedControl
{
if (OwningGrid != null)
{
OwningGrid.OnSublevelIndentUpdated(this, (double)e.NewValue);
OwningGrid.OnSublevelIndentUpdated(this, (double)(e.NewValue ?? 0));
}
}
@@ -198,6 +199,7 @@ public class DataGridRowGroupHeader : TemplatedControl
internal void ApplyHeaderStatus()
{
Debug.Assert(OwningGrid != null);
if (_headerElement != null && OwningGrid.AreRowHeadersVisible)
{
_headerElement.UpdatePseudoClasses();
@@ -278,10 +280,12 @@ public class DataGridRowGroupHeader : TemplatedControl
{
return;
}
Debug.Assert(RowGroupInfo != null);
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
if (OwningGrid.IsDoubleClickRecordsClickOnCall(this) && !e.Handled)
{
ToggleExpandCollapse(!RowGroupInfo.IsVisible, true);
e.Handled = true;
}
@@ -397,6 +401,8 @@ public class DataGridRowGroupHeader : TemplatedControl
internal void ToggleExpandCollapse(bool isVisible, bool setCurrent)
{
Debug.Assert(RowGroupInfo != null);
Debug.Assert(RowGroupInfo.CollectionViewGroup != null);
if (RowGroupInfo.CollectionViewGroup.ItemCount != 0)
{
if (OwningGrid == null)
@@ -426,7 +432,7 @@ public class DataGridRowGroupHeader : TemplatedControl
}
else
{
txt = string.Format("{0}:", PropertyName);
txt = $"{PropertyName}:";
}
_propertyNameElement.Text = txt;
}
@@ -435,11 +441,11 @@ public class DataGridRowGroupHeader : TemplatedControl
string formatString;
if (RowGroupInfo.CollectionViewGroup.ItemCount == 1)
{
formatString = (ItemCountFormat == null ? "({0} Item)" : ItemCountFormat);
formatString = (string.IsNullOrEmpty(ItemCountFormat) ? "({0} Item)" : ItemCountFormat);
}
else
{
formatString = (ItemCountFormat == null ? "({0} Items)" : ItemCountFormat);
formatString = (string.IsNullOrEmpty(ItemCountFormat) ? "({0} Items)" : ItemCountFormat);
}
_itemCountElement.Text = string.Format(formatString, RowGroupInfo.CollectionViewGroup.ItemCount);
}
@@ -69,7 +69,7 @@ public class DataGridRowHeader : ContentControl
{
return OwningRow.Slot;
}
if (OwningRowGroupHeader != null)
if (OwningRowGroupHeader != null && OwningRowGroupHeader.RowGroupInfo != null)
{
return OwningRowGroupHeader.RowGroupInfo.Slot;
}
@@ -150,7 +150,7 @@ public class DataGridRowHeader : ContentControl
PseudoClasses.Set(StdPseudoClass.Current, OwningRow.Slot == OwningGrid.CurrentSlot);
}
}
else if (OwningRowGroupHeader != null && OwningGrid != null)
else if (OwningRowGroupHeader != null && OwningGrid != null && OwningRowGroupHeader.RowGroupInfo != null)
{
PseudoClasses.Set(StdPseudoClass.Current, OwningRowGroupHeader.RowGroupInfo.Slot == OwningGrid.CurrentSlot);
}
@@ -72,6 +72,8 @@ public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider
/// </param>
protected override Size ArrangeOverride(Size finalSize)
{
Debug.Assert(OwningGrid is not null);
Debug.Assert(OwningGrid.ColumnsInternal.FillerColumn is not null);
if (finalSize.Height == 0 || OwningGrid == null)
{
return base.ArrangeOverride(finalSize);
@@ -79,6 +81,7 @@ public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider
if (OwningGrid.RowsPresenterAvailableSize.HasValue)
{
// TODO 需要审查,是否可以删除
var availableHeight = OwningGrid.RowsPresenterAvailableSize.Value.Height;
}
@@ -211,7 +214,7 @@ public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider
}
else if (element is DataGridRowGroupHeader groupHeader)
{
Debug.WriteLine(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Slot: {0} GroupHeader: {1} Visibility: {2}", groupHeader.RowGroupInfo.Slot, groupHeader.RowGroupInfo.CollectionViewGroup.Key, groupHeader.IsVisible));
Debug.WriteLine(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Slot: {0} GroupHeader: {1} Visibility: {2}", groupHeader.RowGroupInfo?.Slot, groupHeader?.RowGroupInfo?.CollectionViewGroup?.Key, groupHeader?.IsVisible));
}
}
}