diff --git a/src/Controls/src/Core/BindableObject.cs b/src/Controls/src/Core/BindableObject.cs
index 40f12defa5fe..955209819ed7 100644
--- a/src/Controls/src/Core/BindableObject.cs
+++ b/src/Controls/src/Core/BindableObject.cs
@@ -399,14 +399,14 @@ protected virtual void OnBindingContextChanged()
///
/// The name of the property that has changed.
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
- => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ => PropertyChanged?.Invoke(this, BindableProperty.GetCachedPropertyChangedEventArgs(propertyName));
///
/// Raises the event.
///
/// The name of the property that is changing.
protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
- => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
+ => PropertyChanging?.Invoke(this, BindableProperty.GetCachedPropertyChangingEventArgs(propertyName));
///
/// Removes all current bindings from the current context.
diff --git a/src/Controls/src/Core/BindableProperty.cs b/src/Controls/src/Core/BindableProperty.cs
index 65c462692249..f8eb6bfc8a89 100644
--- a/src/Controls/src/Core/BindableProperty.cs
+++ b/src/Controls/src/Core/BindableProperty.cs
@@ -1,5 +1,6 @@
#nullable disable
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
@@ -252,6 +253,15 @@ public sealed class BindableProperty
internal ValidateValueDelegate ValidateValue { get; private set; }
+ private static readonly ConcurrentDictionary s_changedArgsCache = new();
+ private static readonly ConcurrentDictionary s_changingArgsCache = new();
+
+ internal static PropertyChangedEventArgs GetCachedPropertyChangedEventArgs(string propertyName)
+ => s_changedArgsCache.GetOrAdd(propertyName, static name => new PropertyChangedEventArgs(name));
+
+ internal static PropertyChangingEventArgs GetCachedPropertyChangingEventArgs(string propertyName)
+ => s_changingArgsCache.GetOrAdd(propertyName, static name => new PropertyChangingEventArgs(name));
+
// Properties that this property depends on - when getting this property's value,
// if the dependency has a pending binding, return the default value instead.
// This is used to fix timing issues where one property binding resolves before another.