mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-22 00:46:48 +08:00
Add DataGridRowHeader
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user