diff --git a/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs b/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs index 9ec256225b..57e4fa4a8e 100644 --- a/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs +++ b/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs @@ -22,7 +22,7 @@ namespace Avalonia.Data.Core if (target is INotifyPropertyChanged inpc) { - WeakEvents.PropertyChanged.Subscribe(inpc, this); + WeakEvents.ThreadSafePropertyChanged.Subscribe(inpc, this); } ValueChanged(GetValue(target)); @@ -39,7 +39,7 @@ namespace Avalonia.Data.Core if (target is INotifyPropertyChanged inpc) { - WeakEvents.PropertyChanged.Unsubscribe(inpc, this); + WeakEvents.ThreadSafePropertyChanged.Unsubscribe(inpc, this); } } } diff --git a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs index 7c2caf02b4..e8e3e6d509 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs @@ -160,7 +160,7 @@ namespace Avalonia.Data.Core.Plugins var inpc = GetReferenceTarget() as INotifyPropertyChanged; if (inpc != null) - WeakEvents.PropertyChanged.Unsubscribe(inpc, this); + WeakEvents.ThreadSafePropertyChanged.Unsubscribe(inpc, this); } private object? GetReferenceTarget() @@ -185,7 +185,7 @@ namespace Avalonia.Data.Core.Plugins var inpc = GetReferenceTarget() as INotifyPropertyChanged; if (inpc != null) - WeakEvents.PropertyChanged.Subscribe(inpc, this); + WeakEvents.ThreadSafePropertyChanged.Subscribe(inpc, this); } } } diff --git a/src/Avalonia.Base/Utilities/WeakEvents.cs b/src/Avalonia.Base/Utilities/WeakEvents.cs index 6da899bab2..2f62564e0e 100644 --- a/src/Avalonia.Base/Utilities/WeakEvents.cs +++ b/src/Avalonia.Base/Utilities/WeakEvents.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Specialized; using System.ComponentModel; using System.Windows.Input; +using Avalonia.Threading; namespace Avalonia.Utilities; @@ -20,15 +21,30 @@ public class WeakEvents }); /// - /// Represents PropertyChanged event from + /// Represents PropertyChanged event from with auto-dispatching to the UI thread /// public static readonly WeakEvent - PropertyChanged = WeakEvent.Register( + ThreadSafePropertyChanged = WeakEvent.Register( (s, h) => { - PropertyChangedEventHandler handler = (_, e) => h(s, e); + bool unsubscribed = false; + PropertyChangedEventHandler handler = (_, e) => + { + if (Dispatcher.UIThread.CheckAccess()) + h(s, e); + else + Dispatcher.UIThread.Post(() => + { + if (!unsubscribed) + h(s, e); + }); + }; s.PropertyChanged += handler; - return () => s.PropertyChanged -= handler; + return () => + { + unsubscribed = true; + s.PropertyChanged -= handler; + }; }); diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs index abb166a92b..9e58f81b55 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs @@ -121,7 +121,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings { if (_reference.TryGetTarget(out var o) && o is INotifyPropertyChanged inpc) { - WeakEvents.PropertyChanged.Unsubscribe(inpc, this); + WeakEvents.ThreadSafePropertyChanged.Unsubscribe(inpc, this); } } @@ -138,7 +138,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings private void SubscribeToChanges() { if (_reference.TryGetTarget(out var o) && o is INotifyPropertyChanged inpc) - WeakEvents.PropertyChanged.Subscribe(inpc, this); + WeakEvents.ThreadSafePropertyChanged.Subscribe(inpc, this); } }