diff --git a/Directory.Build.props b/Directory.Build.props
index 347d4395..9d3235a3 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -8,22 +8,14 @@
false
false
-
-
-
-
true
nullable
-
-
-
-
- $(NoWarn);8604;8602
+ $(NoWarn);NU1903
- 11.0.0
- 11.3.6
+ 12.0.1
+ 12.0.*
diff --git a/build/SourceLink.props b/build/SourceLink.props
index 9b767e54..77d49210 100644
--- a/build/SourceLink.props
+++ b/build/SourceLink.props
@@ -1,4 +1,4 @@
-
+
true
true
@@ -19,7 +19,7 @@
-
+
diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj
index e2ecec09..3f0080ce 100644
--- a/nukebuild/_build.csproj
+++ b/nukebuild/_build.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/samples/TreeDataGridDemo/App.axaml.cs b/samples/TreeDataGridDemo/App.axaml.cs
index cc3d1f15..b2da5c73 100644
--- a/samples/TreeDataGridDemo/App.axaml.cs
+++ b/samples/TreeDataGridDemo/App.axaml.cs
@@ -14,6 +14,8 @@ public override void Initialize()
public override void OnFrameworkInitializationCompleted()
{
+ this.AttachDeveloperTools();
+
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow();
diff --git a/samples/TreeDataGridDemo/MainWindow.axaml.cs b/samples/TreeDataGridDemo/MainWindow.axaml.cs
index 4a1bcdd0..29d82a19 100644
--- a/samples/TreeDataGridDemo/MainWindow.axaml.cs
+++ b/samples/TreeDataGridDemo/MainWindow.axaml.cs
@@ -1,6 +1,5 @@
using System;
using System.Linq;
-using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
@@ -20,7 +19,6 @@ public partial class MainWindow : Window
public MainWindow()
{
InitializeComponent();
- this.AttachDevTools();
DataContext = new MainWindowViewModel();
_tabs = this.FindControl("tabs");
diff --git a/samples/TreeDataGridDemo/TreeDataGridDemo.csproj b/samples/TreeDataGridDemo/TreeDataGridDemo.csproj
index eddf4440..f7ffcce9 100644
--- a/samples/TreeDataGridDemo/TreeDataGridDemo.csproj
+++ b/samples/TreeDataGridDemo/TreeDataGridDemo.csproj
@@ -18,9 +18,9 @@
-
+
diff --git a/samples/TreeDataGridDemo/ViewModels/DynamicColumnsViewModel.cs b/samples/TreeDataGridDemo/ViewModels/DynamicColumnsViewModel.cs
index db2d6e04..b61e9e34 100644
--- a/samples/TreeDataGridDemo/ViewModels/DynamicColumnsViewModel.cs
+++ b/samples/TreeDataGridDemo/ViewModels/DynamicColumnsViewModel.cs
@@ -50,8 +50,8 @@ private void OnColumnCountChanged(int newValue)
{
TextSearchValueSelector = value => value.Value,
IsReadOnlyGetter = value => value.ReadOnly,
- CompareAscending = (a, b) => Comparer.Default.Compare(a.Value, b.Value),
- CompareDescending = (b, a) => Comparer.Default.Compare(a.Value, b.Value),
+ CompareAscending = (a, b) => Comparer.Default.Compare(a?.Value, b?.Value),
+ CompareDescending = (b, a) => Comparer.Default.Compare(a?.Value, b?.Value),
}));
}
}
diff --git a/src/Avalonia.Controls.TreeDataGrid/Avalonia.Controls.TreeDataGrid.csproj b/src/Avalonia.Controls.TreeDataGrid/Avalonia.Controls.TreeDataGrid.csproj
index 07fa28b3..0f966b34 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Avalonia.Controls.TreeDataGrid.csproj
+++ b/src/Avalonia.Controls.TreeDataGrid/Avalonia.Controls.TreeDataGrid.csproj
@@ -1,6 +1,6 @@
- netstandard2.0;net8.0;net10.0;net48
+ net8.0;net10.0
True
Avalonia.Controls
readme.md
@@ -19,23 +19,9 @@
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/MathWrapper.cs b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/MathWrapper.cs
new file mode 100644
index 00000000..9508ca96
--- /dev/null
+++ b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/MathWrapper.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Avalonia.Experimental.Data.Core;
+
+///
+/// Provides math utilities not provided in System.Math.
+///
+internal class MathWrapper
+{
+ // smallest such that 1.0+DoubleEpsilon != 1.0
+ internal const double DoubleEpsilon = 2.2204460492503131e-016;
+
+ internal const float FloatEpsilon = 1.192092896e-07F;
+
+ ///
+ /// AreClose - Returns whether or not two doubles are "close". That is, whether or
+ /// not they are within epsilon of each other.
+ ///
+ /// The first double to compare.
+ /// The second double to compare.
+ public static bool AreClose(double value1, double value2)
+ {
+ //in case they are Infinities (then epsilon check does not work)
+ if (value1 == value2)
+ return true;
+ double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DoubleEpsilon;
+ double delta = value1 - value2;
+ return (-eps < delta) && (eps > delta);
+ }
+
+ ///
+ /// GreaterThan - Returns whether or not the first double is greater than the second double.
+ /// That is, whether or not the first is strictly greater than *and* not within epsilon of
+ /// the other number.
+ ///
+ /// The first double to compare.
+ /// The second double to compare.
+ public static bool GreaterThan(double value1, double value2)
+ {
+ return (value1 > value2) && !AreClose(value1, value2);
+ }
+
+ ///
+ /// IsZero - Returns whether or not the double is "close" to 0. Same as AreClose(double, 0),
+ /// but this is faster.
+ ///
+ /// The double to compare to 0.
+ public static bool IsZero(double value)
+ {
+ return Math.Abs(value) < 10.0 * DoubleEpsilon;
+ }
+}
diff --git a/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/SingleSubscriberObservableBase.cs b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/SingleSubscriberObservableBase.cs
index aa9e0919..c99c6fb7 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/SingleSubscriberObservableBase.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/SingleSubscriberObservableBase.cs
@@ -1,7 +1,7 @@
-using System;
+using System;
using Avalonia.Threading;
-namespace Avalonia.Controls.Experimental.Data.Core;
+namespace Avalonia.Experimental.Data.Core;
internal abstract class SingleSubscriberObservableBase : IObservable, IDisposable
{
diff --git a/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/DataContextRoot.cs b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/DataContextRoot.cs
index cda65e52..8a6d17fe 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/DataContextRoot.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/DataContextRoot.cs
@@ -1,4 +1,4 @@
-using Avalonia.Controls.Experimental.Data.Core;
+using Avalonia.Experimental.Data.Core;
namespace Avalonia.Experimental.Data
{
diff --git a/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/ParentDataContextRoot.cs b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/ParentDataContextRoot.cs
index eb19ded9..05209d24 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/ParentDataContextRoot.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/ParentDataContextRoot.cs
@@ -1,4 +1,4 @@
-using Avalonia.Controls.Experimental.Data.Core;
+using Avalonia.Experimental.Data.Core;
using Avalonia.VisualTree;
namespace Avalonia.Experimental.Data
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousRow.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousRow.cs
index e218f5f5..6829da91 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousRow.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousRow.cs
@@ -17,10 +17,6 @@ internal class AnonymousRow : IRow, IModelIndexableRow
private int _modelIndex;
[AllowNull] private TModel _model;
-#if !NET5_0_OR_GREATER
- object? IRow.Model => _model;
-#endif
-
public object? Header => _modelIndex;
public TModel Model => _model;
public int ModelIndex => _modelIndex;
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousSortableRows.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousSortableRows.cs
index 72c209eb..6444c0eb 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousSortableRows.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousSortableRows.cs
@@ -3,7 +3,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using Avalonia.Controls.Utils;
-using Avalonia.Utilities;
+using Avalonia.Experimental.Data.Core;
namespace Avalonia.Controls.Models.TreeDataGrid
{
@@ -83,7 +83,7 @@ public void Dispose()
{
// Rows in an AnonymousSortableRows collection have Auto height so we only
// know the start position of the first row.
- if (MathUtilities.IsZero(y))
+ if (MathWrapper.IsZero(y))
return (0, 0);
return (-1, -1);
}
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ColumnBase`1.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ColumnBase`1.cs
index f1f8ec67..16b7142d 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ColumnBase`1.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ColumnBase`1.cs
@@ -2,7 +2,7 @@
using System.ComponentModel;
using Avalonia.Data;
using Avalonia.Experimental.Data;
-using Avalonia.Utilities;
+using Avalonia.Experimental.Data.Core;
namespace Avalonia.Controls.Models.TreeDataGrid
{
@@ -156,7 +156,7 @@ void IUpdateColumnLayout.CalculateStarWidth(double availableWidth, double totalS
var width = (availableWidth / totalStars) * Width.Value;
_starWidth = CoerceActualWidth(width);
- _starWidthWasConstrained = !MathUtilities.AreClose(_starWidth, width);
+ _starWidthWasConstrained = !MathWrapper.AreClose(_starWidth, width);
}
bool IUpdateColumnLayout.CommitActualWidth()
@@ -184,7 +184,7 @@ bool IUpdateColumnLayout.CommitActualWidth()
return false;
}
- return !MathUtilities.AreClose(oldWidth, ActualWidth);
+ return !MathWrapper.AreClose(oldWidth, ActualWidth);
}
void IUpdateColumnLayout.SetWidth(GridLength width) => SetWidth(width);
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ColumnList.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ColumnList.cs
index 55495176..28625543 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ColumnList.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ColumnList.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using Avalonia.Collections;
-using Avalonia.Utilities;
+using Avalonia.Experimental.Data.Core;
namespace Avalonia.Controls.Models.TreeDataGrid
{
@@ -160,7 +160,7 @@ private void UpdateColumnSizes()
// If the width of any star columns was constrained by their min/max size, and we
// actually had any space to distribute between star columns, then we need to update
// the star width for the non-constrained columns.
- if (starWidthWasConstrained && MathUtilities.GreaterThan(availableSpace, 0))
+ if (starWidthWasConstrained && MathWrapper.GreaterThan(availableSpace, 0))
{
for (var i = 0; i < Count; ++i)
{
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/DragInfo.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/DragInfo.cs
index f9c31e4b..c9ac82db 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/DragInfo.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/DragInfo.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using Avalonia.Input;
namespace Avalonia.Controls.Models.TreeDataGrid
{
@@ -6,32 +7,23 @@ namespace Avalonia.Controls.Models.TreeDataGrid
/// Holds information about an automatic row drag/drop operation carried out
/// by .
///
- public class DragInfo
+ /// The source of the drag operation/
+ /// The indexes being dragged.
+ public class DragInfo(ITreeDataGridSource source, IEnumerable indexes)
{
///
- /// Defines the data format in an .
+ /// Defines the data format for dragging TreeDataGrid rows.
///
- public const string DataFormat = "TreeDataGridDragInfo";
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The source of the drag operation/
- /// The indexes being dragged.
- public DragInfo(ITreeDataGridSource source, IEnumerable indexes)
- {
- Source = source;
- Indexes = indexes;
- }
+ public static readonly DataFormat Format = DataFormat.CreateInProcessFormat("TreeDataGridDragInfo");
///
/// Gets the that rows are being dragged from.
///
- public ITreeDataGridSource Source { get; }
+ public ITreeDataGridSource Source { get; } = source;
///
/// Gets or sets the model indexes of the rows being dragged.
///
- public IEnumerable Indexes { get; }
+ public IEnumerable Indexes { get; } = indexes;
}
}
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/HierarchicalRow.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/HierarchicalRow.cs
index ddb3f5b2..5e136642 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/HierarchicalRow.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/HierarchicalRow.cs
@@ -22,10 +22,6 @@ public class HierarchicalRow : NotifyingBase,
private bool _isExpanded;
private bool? _showExpander;
-#if !NET5_0_OR_GREATER
- object? IRow.Model => Model;
-#endif
-
public HierarchicalRow(
IExpanderRowController controller,
IExpanderColumn expanderColumn,
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/HierarchicalRows.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/HierarchicalRows.cs
index c8b8bb33..f45c1408 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/HierarchicalRows.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/HierarchicalRows.cs
@@ -2,7 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
-using Avalonia.Utilities;
+using Avalonia.Experimental.Data.Core;
namespace Avalonia.Controls.Models.TreeDataGrid
{
@@ -130,7 +130,7 @@ public void Collapse(IndexPath index)
///
public (int index, double y) GetRowAt(double y)
{
- if (MathUtilities.IsZero(y))
+ if (MathWrapper.IsZero(y))
return (0, 0);
return (-1, -1);
}
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/IRow`1.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/IRow`1.cs
index e4f57b7a..d48b2c0e 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/IRow`1.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/IRow`1.cs
@@ -11,12 +11,10 @@ public interface IRow : IRow
///
new TModel Model { get; }
-#if !!NET5_0_OR_GREATER
///
/// Gets the untyped row model.
///
object? IRow.Model => Model;
-#endif
///
/// Updates the model index due to a change in the data source.
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/IRows.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/IRows.cs
index 30d7670b..c12f66e7 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/IRows.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/IRows.cs
@@ -25,7 +25,7 @@ public interface IRows : IReadOnlyList, INotifyCollectionChanged
(int index, double y) GetRowAt(double y);
///
- /// Given a model index, returns an index into .
+ /// Given a model index, returns an index into .
///
/// The model index.
/// The row index, or -1 if the model index is not displayed.
diff --git a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ShowExpanderObservable.cs b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ShowExpanderObservable.cs
index 3ea0159f..6d73d497 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ShowExpanderObservable.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/ShowExpanderObservable.cs
@@ -2,9 +2,9 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
-using Avalonia.Controls.Experimental.Data.Core;
using Avalonia.Data;
using Avalonia.Experimental.Data;
+using Avalonia.Experimental.Data.Core;
namespace Avalonia.Controls.Models.TreeDataGrid
{
diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/RealizedStackElements.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/RealizedStackElements.cs
index 836c81fb..1c1fcb26 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Primitives/RealizedStackElements.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/RealizedStackElements.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using Avalonia.Controls.Models.TreeDataGrid;
-using Avalonia.Utilities;
+using Avalonia.Experimental.Data.Core;
namespace Avalonia.Controls.Primitives
{
@@ -128,7 +128,7 @@ public void Add(int index, Control element, double u, double sizeU)
return (-1, 0);
// If we're at 0 then display the first item.
- if (MathUtilities.IsZero(viewportStartU))
+ if (MathWrapper.IsZero(viewportStartU))
return (0, 0);
if (_sizes is not null && !_startUUnstable)
diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCell.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCell.cs
index 3e149cb6..524ecf37 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCell.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCell.cs
@@ -4,7 +4,6 @@
using Avalonia.Controls.Models.TreeDataGrid;
using Avalonia.Controls.Selection;
using Avalonia.Input;
-using Avalonia.Interactivity;
using Avalonia.LogicalTree;
using Avalonia.VisualTree;
@@ -143,7 +142,7 @@ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
_treeDataGrid.RaiseCellPrepared(this, ColumnIndex, RowIndex);
}
- protected override void OnLostFocus(RoutedEventArgs e)
+ protected override void OnLostFocus(FocusChangedEventArgs e)
{
base.OnLostFocus(e);
@@ -163,7 +162,7 @@ protected override Size MeasureOverride(Size availableSize)
return result;
}
- protected virtual void OnDoubleTapped(TappedEventArgs e)
+ protected override void OnDoubleTapped(TappedEventArgs e)
{
if (Model is not null &&
!e.Handled &&
@@ -238,7 +237,7 @@ protected override void OnPointerReleased(PointerReleasedEventArgs e)
IsEnabledEditGesture(BeginEditGestures.Tap, Model.EditGestures))
{
var point = e.GetCurrentPoint(this);
- var settings = TopLevel.GetTopLevel(this)?.PlatformSettings;
+ var settings = this.GetPlatformSettings();
var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4);
var tapRect = new Rect(_pressedPoint, new Size())
.Inflate(new Thickness(tapSize.Width, tapSize.Height));
diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeader.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeader.cs
index c9cf22de..e1d11bb7 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeader.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridColumnHeader.cs
@@ -1,8 +1,8 @@
using System;
using System.ComponentModel;
using Avalonia.Controls.Models.TreeDataGrid;
+using Avalonia.Experimental.Data.Core;
using Avalonia.Input;
-using Avalonia.Utilities;
namespace Avalonia.Controls.Primitives
{
@@ -160,7 +160,7 @@ private void OnOwnerPropertyChanged(object? sender, AvaloniaPropertyChangedEvent
private void ResizerDragDelta(object? sender, VectorEventArgs e)
{
- if (_columns is null || _model is null || MathUtilities.IsZero(e.Vector.X))
+ if (_columns is null || _model is null || MathWrapper.IsZero(e.Vector.X))
return;
var pixelWidth = _model.Width.IsAbsolute ? _model.Width.Value : Bounds.Width;
diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs
index e5d03e37..6458716c 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs
@@ -4,10 +4,10 @@
using System.Data;
using System.Diagnostics;
using System.Linq;
+using Avalonia.Experimental.Data.Core;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.LogicalTree;
-using Avalonia.Utilities;
using Avalonia.VisualTree;
using CollectionExtensions = Avalonia.Controls.Models.TreeDataGrid.CollectionExtensions;
@@ -215,7 +215,7 @@ protected virtual Size MeasureElement(int index, Control element, Size available
/// - The final pass is made once the "natural" sizes of the elements are known and any
/// layout logic has been run. This pass is needed because controls should not be
/// arranged with a size less than that passed as the constraint during the measure
- /// pass. This pass is only run if returns
+ /// pass. This pass is only run if returns
/// true.
///
protected virtual Size GetInitialConstraint(
@@ -457,8 +457,8 @@ protected virtual void OnEffectiveViewportChanged(object? sender, EffectiveViewp
var newViewportStart = vertical ? Viewport.Top : Viewport.Left;
var newViewportEnd = vertical ? Viewport.Bottom : Viewport.Right;
- if (!MathUtilities.AreClose(oldViewportStart, newViewportStart) ||
- !MathUtilities.AreClose(oldViewportEnd, newViewportEnd))
+ if (!MathWrapper.AreClose(oldViewportStart, newViewportStart) ||
+ !MathWrapper.AreClose(oldViewportEnd, newViewportEnd))
{
InvalidateMeasure();
}
diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRow.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRow.cs
index 7b60a319..0972b4e6 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRow.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRow.cs
@@ -11,7 +11,6 @@ namespace Avalonia.Controls.Primitives
public class TreeDataGridRow : TemplatedControl
{
private const double DragDistance = 3;
- private static readonly Point s_InvalidPoint = new(double.NegativeInfinity, double.NegativeInfinity);
public static readonly DirectProperty ColumnsProperty =
AvaloniaProperty.RegisterDirect(
@@ -38,7 +37,7 @@ public class TreeDataGridRow : TemplatedControl
private TreeDataGridElementFactory? _elementFactory;
private bool _isSelected;
private IRows? _rows;
- private Point _mouseDownPosition = s_InvalidPoint;
+ private (Point position, PointerPressedEventArgs eventArgs)? _mouseDownInfo = null;
private TreeDataGrid? _treeDataGrid;
public IColumns? Columns
@@ -144,15 +143,22 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
- _mouseDownPosition = !e.Handled ? e.GetPosition(this) : s_InvalidPoint;
+
+ if (!e.Handled)
+ _mouseDownInfo = (e.GetPosition(this), e);
}
protected override void OnPointerMoved(PointerEventArgs e)
{
base.OnPointerMoved(e);
+ if (!_mouseDownInfo.HasValue ||
+ e.Handled)
+ return;
+
+ var (mouseDownPoint, eventArgs) = _mouseDownInfo.Value;
var currentPoint = e.GetCurrentPoint(this);
- var delta = currentPoint.Position - _mouseDownPosition;
+ var delta = currentPoint.Position - mouseDownPoint;
var pointerSupportsDrag = currentPoint.Pointer.Type switch
{
@@ -162,28 +168,26 @@ protected override void OnPointerMoved(PointerEventArgs e)
};
if (!pointerSupportsDrag ||
- e.Handled ||
- Math.Abs(delta.X) < DragDistance && Math.Abs(delta.Y) < DragDistance ||
- _mouseDownPosition == s_InvalidPoint)
+ Math.Abs(delta.X) < DragDistance && Math.Abs(delta.Y) < DragDistance)
return;
- _mouseDownPosition = s_InvalidPoint;
+ _mouseDownInfo = default;
var presenter = Parent as TreeDataGridRowsPresenter;
var owner = presenter?.TemplatedParent as TreeDataGrid;
- owner?.RaiseRowDragStarted(e);
+ owner?.RaiseRowDragStarted(eventArgs);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
- _mouseDownPosition = s_InvalidPoint;
+ _mouseDownInfo = default;
}
protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e)
{
base.OnPointerCaptureLost(e);
- _mouseDownPosition = s_InvalidPoint;
+ _mouseDownInfo = default;
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridTemplateCell.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridTemplateCell.cs
index 0431929c..4db78f10 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridTemplateCell.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridTemplateCell.cs
@@ -127,7 +127,7 @@ protected override void OnDataContextChanged(EventArgs e)
}
}
- protected override void OnLostFocus(RoutedEventArgs e)
+ protected override void OnLostFocus(FocusChangedEventArgs e)
{
if (EndEditIfFocusLost())
{
diff --git a/src/Avalonia.Controls.TreeDataGrid/Selection/TreeDataGridCellSelectionModel.cs b/src/Avalonia.Controls.TreeDataGrid/Selection/TreeDataGridCellSelectionModel.cs
index 6f87d485..cbe1de64 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Selection/TreeDataGridCellSelectionModel.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Selection/TreeDataGridCellSelectionModel.cs
@@ -128,13 +128,8 @@ sender.Rows is null ||
var anchor = shift ? _rangeAnchor : GetAnchor();
-#if !NET5_0_OR_GREATER
- var columnIndex = Math.Min(Math.Max(anchor.x + x, 0), sender.Columns.Count - 1);
- var rowIndex = Math.Min(Math.Max(anchor.y + y, 0), sender.Rows.Count - 1);
-#else
var columnIndex = Math.Clamp(anchor.x + x, 0, sender.Columns.Count - 1);
var rowIndex = Math.Clamp(anchor.y + y, 0, sender.Rows.Count - 1);
-#endif
if (!shift)
Select(columnIndex, rowIndex);
diff --git a/src/Avalonia.Controls.TreeDataGrid/Selection/TreeDataGridRowSelectionModel.cs b/src/Avalonia.Controls.TreeDataGrid/Selection/TreeDataGridRowSelectionModel.cs
index dabbbe4f..80780edb 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Selection/TreeDataGridRowSelectionModel.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Selection/TreeDataGridRowSelectionModel.cs
@@ -391,8 +391,8 @@ private void PointerSelect(TreeDataGrid sender, TreeDataGridRow row, PointerEven
{
var point = e.GetCurrentPoint(sender);
- var commandModifiers = TopLevel.GetTopLevel(sender)?.PlatformSettings?.HotkeyConfiguration.CommandModifiers;
- var toggleModifier = commandModifiers is not null && e.KeyModifiers.HasFlag(commandModifiers);
+ var commandModifiers = sender.GetPlatformSettings()?.HotkeyConfiguration.CommandModifiers;
+ var toggleModifier = commandModifiers.HasValue && e.KeyModifiers.HasFlag(commandModifiers.Value);
var isRightButton = point.Properties.PointerUpdateKind is PointerUpdateKind.RightButtonPressed or
PointerUpdateKind.RightButtonReleased;
diff --git a/src/Avalonia.Controls.TreeDataGrid/StandardExtensions/BitOperations.cs b/src/Avalonia.Controls.TreeDataGrid/StandardExtensions/BitOperations.cs
deleted file mode 100644
index cb38ed25..00000000
--- a/src/Avalonia.Controls.TreeDataGrid/StandardExtensions/BitOperations.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Runtime.CompilerServices;
-
-// Some routines inspired by the Stanford Bit Twiddling Hacks by Sean Eron Anderson:
-// http://graphics.stanford.edu/~seander/bithacks.html
-
-namespace System.Numerics
-{
- ///
- /// Utility methods for intrinsic bit-twiddling operations.
- /// The methods use hardware intrinsics when available on the underlying platform,
- /// otherwise they use optimized software fallbacks.
- ///
- internal static class BitOperations
- {
- // C# no-alloc optimization that directly wraps the data section of the dll (similar to string constants)
- // https://github.com/dotnet/roslyn/pull/24621
-
- private static ReadOnlySpan Log2DeBruijn => // 32
- [
- 00, 09, 01, 10, 13, 21, 02, 29,
- 11, 14, 16, 18, 22, 25, 03, 30,
- 08, 12, 20, 28, 15, 17, 24, 07,
- 19, 27, 23, 06, 26, 05, 04, 31
- ];
-
- ///
- /// Returns the integer (floor) log of the specified value, base 2.
- /// Note that by convention, input value 0 returns 0 since log(0) is undefined.
- ///
- /// The value.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int Log2(uint value)
- {
- // The 0->0 contract is fulfilled by setting the LSB to 1.
- // Log(1) is 0, and setting the LSB for values > 1 does not change the log2 result.
- value |= 1;
-
- // Fallback contract is 0->0
- return Log2SoftwareFallback(value);
- }
-
- ///
- /// Returns the integer (floor) log of the specified value, base 2.
- /// Note that by convention, input value 0 returns 0 since Log(0) is undefined.
- /// Does not directly use any hardware intrinsics, nor does it incur branching.
- ///
- /// The value.
- private static int Log2SoftwareFallback(uint value)
- {
- // No AggressiveInlining due to large method size
- // Has conventional contract 0->0 (Log(0) is undefined)
-
- // Fill trailing zeros with ones, eg 00010010 becomes 00011111
- value |= value >> 01;
- value |= value >> 02;
- value |= value >> 04;
- value |= value >> 08;
- value |= value >> 16;
-
- // Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_1100_0100_1010_1100_1101_1101u
- return Log2DeBruijn[(int)((value * 0x07C4ACDDu) >> 27)];
- }
- }
-}
diff --git a/src/Avalonia.Controls.TreeDataGrid/StandardExtensions/Double.cs b/src/Avalonia.Controls.TreeDataGrid/StandardExtensions/Double.cs
deleted file mode 100644
index a465956c..00000000
--- a/src/Avalonia.Controls.TreeDataGrid/StandardExtensions/Double.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Runtime.CompilerServices;
-
-namespace Avalonia;
-
-
-internal static class Double
-{
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool IsFinite(double value)
- {
- return !double.IsNaN(value) && !double.IsInfinity(value);
- }
-}
diff --git a/src/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs b/src/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs
index db5f3570..c38457aa 100644
--- a/src/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs
@@ -7,10 +7,10 @@
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Selection;
using Avalonia.Controls.Shapes;
+using Avalonia.Experimental.Data.Core;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Threading;
-using Avalonia.Utilities;
using Avalonia.VisualTree;
namespace Avalonia.Controls
@@ -519,7 +519,7 @@ internal void RaiseRowPrepared(TreeDataGridRow row, int rowIndex)
}
}
- internal void RaiseRowDragStarted(PointerEventArgs trigger)
+ internal void RaiseRowDragStarted(PointerPressedEventArgs trigger)
{
if (_source is null || RowSelection is null)
return;
@@ -539,10 +539,12 @@ internal void RaiseRowDragStarted(PointerEventArgs trigger)
if (allowedEffects != DragDropEffects.None)
{
- var data = new DataObject();
+ var dataTransfer = new DataTransfer();
var info = new DragInfo(_source, RowSelection.SelectedIndexes.ToList());
- data.Set(DragInfo.DataFormat, info);
- DragDrop.DoDragDrop(trigger, data, allowedEffects);
+ var item = new DataTransferItem();
+ item.Set(DragInfo.Format, info);
+ dataTransfer.Add(item);
+ _ = DragDrop.DoDragDropAsync(trigger, dataTransfer, allowedEffects);
}
}
@@ -675,9 +677,7 @@ private void AutoScroll(bool direction)
_autoScrollTimer.Start();
}
-#if NET5_0_OR_GREATER
[MemberNotNullWhen(true, nameof(_source))]
-#endif
private bool CalculateAutoDragDrop(
TreeDataGridRow? targetRow,
DragEventArgs e,
@@ -685,7 +685,7 @@ private bool CalculateAutoDragDrop(
out TreeDataGridRowDropPosition position)
{
if (!AutoDragDropRows ||
- e.Data.Get(DragInfo.DataFormat) is not DragInfo di ||
+ e.DataTransfer.TryGetValues(DragInfo.Format)?.FirstOrDefault() is not DragInfo di ||
_source is null ||
_source.IsSorted ||
targetRow is null ||
@@ -791,13 +791,13 @@ row is not null &&
private void OnScrollChanged(object? sender, ScrollChangedEventArgs e)
{
- if (Scroll is not null && _headerScroll is not null && !MathUtilities.IsZero(e.OffsetDelta.X))
+ if (Scroll is not null && _headerScroll is not null && !MathWrapper.IsZero(e.OffsetDelta.X))
_headerScroll.Offset = _headerScroll.Offset.WithX(Scroll.Offset.X);
}
private void OnHeaderScrollChanged(object? sender, ScrollChangedEventArgs e)
{
- if (Scroll is not null && _headerScroll is not null && !MathUtilities.IsZero(e.OffsetDelta.X))
+ if (Scroll is not null && _headerScroll is not null && !MathWrapper.IsZero(e.OffsetDelta.X))
Scroll.Offset = Scroll.Offset.WithX(_headerScroll.Offset.X);
}
diff --git a/src/Avalonia.Controls.TreeDataGrid/Utils/StableSort.cs b/src/Avalonia.Controls.TreeDataGrid/Utils/StableSort.cs
index 9597e4fb..c34aee36 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Utils/StableSort.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Utils/StableSort.cs
@@ -19,12 +19,8 @@ public static List SortedMap(IReadOnlyList elements, Comparison
map.Add(i);
}
-#if !NET5_0_OR_GREATER
- map.Sort(compare);
-#else
var span = CollectionsMarshal.AsSpan(map);
SortHelper.Sort(span, compare);
-#endif
return map;
}
diff --git a/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Avalonia.Controls.TreeDataGrid.Benchmark.csproj b/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Avalonia.Controls.TreeDataGrid.Benchmark.csproj
index 61b5d8ac..6798ad7e 100644
--- a/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Avalonia.Controls.TreeDataGrid.Benchmark.csproj
+++ b/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Avalonia.Controls.TreeDataGrid.Benchmark.csproj
@@ -1,7 +1,7 @@
- net48;net10.0
+ net10.0
Exe
Avalonia.Controls.TreeDataGridBenchmark
@@ -16,13 +16,7 @@
-
-
- TargetFramework=net48
-
-
-
-
+
diff --git a/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Benchmarks.cs b/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Benchmarks.cs
index 2e0e6590..c0bb1a29 100644
--- a/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Benchmarks.cs
+++ b/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Benchmarks.cs
@@ -16,7 +16,7 @@ public class Benchmarks
private const int RowCount = 500;
private const int ColumnCount = 40;
- private TreeDataGrid? _target;
+ private TreeDataGrid _target = default!;
[GlobalSetup]
public void Setup()
diff --git a/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Program.cs b/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Program.cs
index c5f7c5b7..9607faed 100644
--- a/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Program.cs
+++ b/tests/Avalonia.Controls.TreeDataGrid.Benchmark/Program.cs
@@ -1,7 +1,5 @@
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
-using BenchmarkDotNet.Environments;
-using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
namespace Avalonia.Controls.TreeDataGridBenchmark;
@@ -11,8 +9,6 @@ internal class Program
private static void Main(string[] args)
{
var _ = BenchmarkRunner.Run(typeof(Program).Assembly, DefaultConfig.Instance
- .AddJob(Job.Default.WithRuntime(ClrRuntime.Net48))
- .AddJob(Job.Default.WithRuntime(CoreRuntime.Core10_0))
.AddDiagnoser(MemoryDiagnoser.Default));
}
}
diff --git a/tests/Avalonia.Controls.TreeDataGrid.Tests/Avalonia.Controls.TreeDataGrid.Tests.csproj b/tests/Avalonia.Controls.TreeDataGrid.Tests/Avalonia.Controls.TreeDataGrid.Tests.csproj
index 792a5b65..3766cb05 100644
--- a/tests/Avalonia.Controls.TreeDataGrid.Tests/Avalonia.Controls.TreeDataGrid.Tests.csproj
+++ b/tests/Avalonia.Controls.TreeDataGrid.Tests/Avalonia.Controls.TreeDataGrid.Tests.csproj
@@ -7,12 +7,12 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/tests/Avalonia.Controls.TreeDataGrid.Tests/FlatTreeDataGridSourceTests.cs b/tests/Avalonia.Controls.TreeDataGrid.Tests/FlatTreeDataGridSourceTests.cs
index 2f70c5d1..48632b24 100644
--- a/tests/Avalonia.Controls.TreeDataGrid.Tests/FlatTreeDataGridSourceTests.cs
+++ b/tests/Avalonia.Controls.TreeDataGrid.Tests/FlatTreeDataGridSourceTests.cs
@@ -199,6 +199,7 @@ public void Supports_Adding_Row()
{
Assert.Equal(NotifyCollectionChangedAction.Add, e.Action);
Assert.Equal(0, e.NewStartingIndex);
+ Assert.NotNull(e.NewItems);
Assert.Single(e.NewItems);
Assert.Equal(10, ((IModelIndexableRow)e.NewItems[0]!).ModelIndex);
++raised;
@@ -225,7 +226,8 @@ public void Supports_Removing_Row()
{
Assert.Equal(NotifyCollectionChangedAction.Remove, e.Action);
Assert.Equal(4, e.OldStartingIndex);
- Assert.Single(e.OldItems!);
+ Assert.NotNull(e.OldItems);
+ Assert.Single(e.OldItems);
Assert.Equal(5, ((IModelIndexableRow)e.OldItems[0]!).ModelIndex);
++raised;
};
diff --git a/tests/Avalonia.Controls.TreeDataGrid.Tests/Primitives/TreeDataGridRowsPresenterTests.cs b/tests/Avalonia.Controls.TreeDataGrid.Tests/Primitives/TreeDataGridRowsPresenterTests.cs
index f492a8c0..590f379a 100644
--- a/tests/Avalonia.Controls.TreeDataGrid.Tests/Primitives/TreeDataGridRowsPresenterTests.cs
+++ b/tests/Avalonia.Controls.TreeDataGrid.Tests/Primitives/TreeDataGridRowsPresenterTests.cs
@@ -226,6 +226,7 @@ public void Should_Remove_Children_On_Empty_Collection_Assignment_To_Items()
Assert.Equal(100, items.Count);
items.RemoveRange(1, 99);
Layout(target);
+ Assert.NotNull(target.Items);
Assert.Single(target.Items);
Assert.Single(target.GetVisualChildren());
diff --git a/tests/Avalonia.Controls.TreeDataGrid.Tests/Selection/TreeSelectionModelBaseTests_Multiple.cs b/tests/Avalonia.Controls.TreeDataGrid.Tests/Selection/TreeSelectionModelBaseTests_Multiple.cs
index c0ddda08..77c30011 100644
--- a/tests/Avalonia.Controls.TreeDataGrid.Tests/Selection/TreeSelectionModelBaseTests_Multiple.cs
+++ b/tests/Avalonia.Controls.TreeDataGrid.Tests/Selection/TreeSelectionModelBaseTests_Multiple.cs
@@ -1502,7 +1502,9 @@ public void Clearing_Node_Selection_Unsubscribes_From_CollectionChanged()
target.Select(new IndexPath(1, 1));
var debug = (AvaloniaListDebug)data[1].Children!;
- Assert.Single(debug.GetCollectionChangedSubscribers());
+ var subs = debug.GetCollectionChangedSubscribers();
+ Assert.NotNull(subs);
+ Assert.Single(subs);
target.Deselect(new IndexPath(1, 1));
diff --git a/tests/Avalonia.Controls.TreeDataGrid.Tests/TreeDataGridTests_Flat.cs b/tests/Avalonia.Controls.TreeDataGrid.Tests/TreeDataGridTests_Flat.cs
index 11b7e997..f4b636e3 100644
--- a/tests/Avalonia.Controls.TreeDataGrid.Tests/TreeDataGridTests_Flat.cs
+++ b/tests/Avalonia.Controls.TreeDataGrid.Tests/TreeDataGridTests_Flat.cs
@@ -424,7 +424,7 @@ public void Header_Column_Indexes_Are_Updated_When_Columns_Are_Updated()
source.Columns.Add(movedColumn);
- var root = (TestWindow)target.GetVisualRoot()!;
+ var root = (TestWindow)target.Parent!;
root.UpdateLayout();
Dispatcher.UIThread.RunJobs();