diff --git a/Directory.Build.props b/Directory.Build.props
index 649c7114..347d4395 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -10,12 +10,14 @@
false
-
+
+
true
nullable
-
+
+
$(NoWarn);8604;8602
diff --git a/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/LightweightObservableBase.cs b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/LightweightObservableBase.cs
index 88f58b78..1caed2a1 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/LightweightObservableBase.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Experimental/Data/Core/LightweightObservableBase.cs
@@ -1,4 +1,5 @@
-using System;
+using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Threading;
@@ -19,7 +20,7 @@ public abstract class LightweightObservableBase : IObservable
private List>? _observers = [];
public bool HasObservers => _observers?.Count > 0;
-
+
public IDisposable Subscribe(IObserver observer)
{
_ = observer ?? throw new ArgumentNullException(nameof(observer));
@@ -117,32 +118,61 @@ protected void PublishNext(T value)
if (Volatile.Read(ref _observers) != null)
{
IObserver[]? observers = null;
- IObserver? singleObserver = null;
+ int count = 0;
+
+ // Optimize for the common case of 1/2/3 observers.
+ IObserver? observer0 = null;
+ IObserver? observer1 = null;
+ IObserver? observer2 = null;
lock (this)
{
if (_observers == null)
{
return;
}
- if (_observers.Count == 1)
- {
- singleObserver = _observers[0];
- }
- else
+
+ count = _observers.Count;
+ switch (count)
{
- observers = _observers.ToArray();
+ case 3:
+ observer0 = _observers[0];
+ observer1 = _observers[1];
+ observer2 = _observers[2];
+ break;
+ case 2:
+ observer0 = _observers[0];
+ observer1 = _observers[1];
+ break;
+ case 1:
+ observer0 = _observers[0];
+ break;
+ case 0:
+ return;
+ default:
+ {
+ observers = ArrayPool>.Shared.Rent(count);
+ _observers.CopyTo(observers);
+ break;
+ }
}
}
- if (singleObserver != null)
+
+ if (observer0 != null)
{
- singleObserver.OnNext(value);
+ observer0.OnNext(value);
+ observer1?.OnNext(value);
+ observer2?.OnNext(value);
}
- else
+ else if (observers != null)
{
- foreach (var observer in observers!)
+ for (int i = 0; i < count; i++)
{
- observer.OnNext(value);
+ observers[i].OnNext(value);
+ // Avoid memory leak by clearing the reference.
+ observers[i] = null!;
}
+
+ ArrayPool>.Shared.Return(observers);
}
}
}
diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs
index b796da24..beb18c7f 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs
@@ -739,8 +739,8 @@ private void RecycleElementOnItemRemoved(Control element)
_focusedIndex = -1;
}
- UnrealizeElementOnItemRemoved(element);
element.IsVisible = false;
+ UnrealizeElementOnItemRemoved(element);
ElementFactory!.RecycleElement(element);
_scrollViewer?.UnregisterAnchorCandidate(element);
}
diff --git a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridTextCell.cs b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridTextCell.cs
index 189e2317..168eebcb 100644
--- a/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridTextCell.cs
+++ b/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridTextCell.cs
@@ -1,6 +1,4 @@
using System.ComponentModel;
-using System.Globalization;
-using System.Reflection;
using Avalonia.Controls.Models.TreeDataGrid;
using Avalonia.Controls.Selection;
using Avalonia.Media;