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.