diff --git a/src/Avalonia.Base/ApiCompatBaseline.txt b/src/Avalonia.Base/ApiCompatBaseline.txt index 4701a83175d..d698cfb91e3 100644 --- a/src/Avalonia.Base/ApiCompatBaseline.txt +++ b/src/Avalonia.Base/ApiCompatBaseline.txt @@ -1,3 +1,57 @@ Compat issues with assembly Avalonia.Base: +MembersMustExist : Member 'public void Avalonia.AvaloniaObject.CoerceValue(Avalonia.StyledPropertyBase)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'protected Avalonia.IAvaloniaObject Avalonia.AvaloniaObject.InheritanceParent.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'protected void Avalonia.AvaloniaObject.InheritanceParent.set(Avalonia.IAvaloniaObject)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.AvaloniaObject.SetValue(Avalonia.AvaloniaProperty, System.Object, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.IDisposable Avalonia.AvaloniaObjectExtensions.Bind(Avalonia.IAvaloniaObject, Avalonia.AvaloniaProperty, System.IObservable>, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.IDisposable Avalonia.AvaloniaObjectExtensions.Bind(Avalonia.IAvaloniaObject, Avalonia.AvaloniaProperty, System.IObservable, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.AvaloniaObjectExtensions.ClearValue(Avalonia.IAvaloniaObject, Avalonia.AvaloniaProperty)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.AvaloniaObjectExtensions.ClearValue(Avalonia.IAvaloniaObject, Avalonia.AvaloniaProperty)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Object Avalonia.AvaloniaObjectExtensions.GetValue(Avalonia.IAvaloniaObject, Avalonia.AvaloniaProperty)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.IDisposable Avalonia.AvaloniaObjectExtensions.SetValue(Avalonia.IAvaloniaObject, Avalonia.AvaloniaProperty, System.Object, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.IDisposable Avalonia.AvaloniaObjectExtensions.SetValue(Avalonia.IAvaloniaObject, Avalonia.AvaloniaProperty, T, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +CannotAddAbstractMembers : Member 'internal System.IDisposable Avalonia.AvaloniaProperty.RouteBind(Avalonia.AvaloniaObject, System.IObservable>, Avalonia.Data.BindingPriority)' is abstract in the implementation but is missing in the contract. +MembersMustExist : Member 'internal System.IDisposable Avalonia.AvaloniaProperty.RouteBind(Avalonia.IAvaloniaObject, System.IObservable>, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +CannotAddAbstractMembers : Member 'internal void Avalonia.AvaloniaProperty.RouteClearValue(Avalonia.AvaloniaObject)' is abstract in the implementation but is missing in the contract. +MembersMustExist : Member 'internal void Avalonia.AvaloniaProperty.RouteClearValue(Avalonia.IAvaloniaObject)' does not exist in the implementation but it does exist in the contract. +CannotAddAbstractMembers : Member 'internal System.Object Avalonia.AvaloniaProperty.RouteGetBaseValue(Avalonia.AvaloniaObject, Avalonia.Data.BindingPriority)' is abstract in the implementation but is missing in the contract. +MembersMustExist : Member 'internal System.Object Avalonia.AvaloniaProperty.RouteGetBaseValue(Avalonia.IAvaloniaObject, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +CannotAddAbstractMembers : Member 'internal System.Object Avalonia.AvaloniaProperty.RouteGetValue(Avalonia.AvaloniaObject)' is abstract in the implementation but is missing in the contract. +MembersMustExist : Member 'internal System.Object Avalonia.AvaloniaProperty.RouteGetValue(Avalonia.IAvaloniaObject)' does not exist in the implementation but it does exist in the contract. +CannotAddAbstractMembers : Member 'internal void Avalonia.AvaloniaProperty.RouteInheritanceParentChanged(Avalonia.AvaloniaObject, Avalonia.AvaloniaObject)' is abstract in the implementation but is missing in the contract. +MembersMustExist : Member 'internal void Avalonia.AvaloniaProperty.RouteInheritanceParentChanged(Avalonia.AvaloniaObject, Avalonia.IAvaloniaObject)' does not exist in the implementation but it does exist in the contract. +CannotAddAbstractMembers : Member 'internal System.IDisposable Avalonia.AvaloniaProperty.RouteSetValue(Avalonia.AvaloniaObject, System.Object, Avalonia.Data.BindingPriority)' is abstract in the implementation but is missing in the contract. +MembersMustExist : Member 'internal System.IDisposable Avalonia.AvaloniaProperty.RouteSetValue(Avalonia.IAvaloniaObject, System.Object, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.IAvaloniaObject.AddInheritanceChild(Avalonia.IAvaloniaObject)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public void Avalonia.IAvaloniaObject.AddInheritanceChild(Avalonia.IAvaloniaObject)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.IDisposable Avalonia.IAvaloniaObject.Bind(Avalonia.AvaloniaProperty, System.IObservable, Avalonia.Data.BindingPriority)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.IDisposable Avalonia.IAvaloniaObject.Bind(Avalonia.DirectPropertyBase, System.IObservable>)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.IDisposable Avalonia.IAvaloniaObject.Bind(Avalonia.DirectPropertyBase, System.IObservable>)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.IDisposable Avalonia.IAvaloniaObject.Bind(Avalonia.StyledPropertyBase, System.IObservable>, Avalonia.Data.BindingPriority)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.IDisposable Avalonia.IAvaloniaObject.Bind(Avalonia.StyledPropertyBase, System.IObservable>, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.IAvaloniaObject.ClearValue(Avalonia.AvaloniaProperty)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.IAvaloniaObject.ClearValue(Avalonia.DirectPropertyBase)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public void Avalonia.IAvaloniaObject.ClearValue(Avalonia.DirectPropertyBase)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.IAvaloniaObject.ClearValue(Avalonia.StyledPropertyBase)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public void Avalonia.IAvaloniaObject.ClearValue(Avalonia.StyledPropertyBase)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.IAvaloniaObject.CoerceValue(Avalonia.AvaloniaProperty)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.IAvaloniaObject.CoerceValue(Avalonia.StyledPropertyBase)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public void Avalonia.IAvaloniaObject.CoerceValue(Avalonia.StyledPropertyBase)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Data.Optional Avalonia.IAvaloniaObject.GetBaseValue(Avalonia.StyledPropertyBase, Avalonia.Data.BindingPriority)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public Avalonia.Data.Optional Avalonia.IAvaloniaObject.GetBaseValue(Avalonia.StyledPropertyBase, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Object Avalonia.IAvaloniaObject.GetValue(Avalonia.AvaloniaProperty)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public T Avalonia.IAvaloniaObject.GetValue(Avalonia.DirectPropertyBase)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public T Avalonia.IAvaloniaObject.GetValue(Avalonia.DirectPropertyBase)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public T Avalonia.IAvaloniaObject.GetValue(Avalonia.StyledPropertyBase)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public T Avalonia.IAvaloniaObject.GetValue(Avalonia.StyledPropertyBase)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.IAvaloniaObject.InheritedPropertyChanged(Avalonia.AvaloniaProperty, Avalonia.Data.Optional, Avalonia.Data.Optional)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public void Avalonia.IAvaloniaObject.InheritedPropertyChanged(Avalonia.AvaloniaProperty, Avalonia.Data.Optional, Avalonia.Data.Optional)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.IAvaloniaObject.RemoveInheritanceChild(Avalonia.IAvaloniaObject)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public void Avalonia.IAvaloniaObject.RemoveInheritanceChild(Avalonia.IAvaloniaObject)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.IDisposable Avalonia.IAvaloniaObject.SetValue(Avalonia.AvaloniaProperty, System.Object, Avalonia.Data.BindingPriority)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.IAvaloniaObject.SetValue(Avalonia.DirectPropertyBase, T)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public void Avalonia.IAvaloniaObject.SetValue(Avalonia.DirectPropertyBase, T)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.IDisposable Avalonia.IAvaloniaObject.SetValue(Avalonia.StyledPropertyBase, T, Avalonia.Data.BindingPriority)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.IDisposable Avalonia.IAvaloniaObject.SetValue(Avalonia.StyledPropertyBase, T, Avalonia.Data.BindingPriority)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Threading.IDispatcher.Post(System.Action, T, Avalonia.Threading.DispatcherPriority)' is present in the implementation but not in the contract. -Total Issues: 1 +Total Issues: 55 diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index 437339d3b2c..e243b0f5526 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/src/Avalonia.Base/AvaloniaObject.cs @@ -5,6 +5,7 @@ using Avalonia.Diagnostics; using Avalonia.Logging; using Avalonia.PropertyStore; +using Avalonia.Reactive; using Avalonia.Threading; namespace Avalonia @@ -17,11 +18,11 @@ namespace Avalonia /// public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged, IValueSink { - private IAvaloniaObject? _inheritanceParent; + private AvaloniaObject? _inheritanceParent; private List? _directBindings; private PropertyChangedEventHandler? _inpcChanged; private EventHandler? _propertyChanged; - private List? _inheritanceChildren; + private List? _inheritanceChildren; private ValueStore? _values; private bool _batchUpdate; @@ -58,7 +59,7 @@ event PropertyChangedEventHandler? INotifyPropertyChanged.PropertyChanged /// /// The inheritance parent. /// - protected IAvaloniaObject? InheritanceParent + protected AvaloniaObject? InheritanceParent { get { @@ -320,14 +321,14 @@ public bool IsSet(AvaloniaProperty property) /// The property. /// The value. /// The priority of the value. - public void SetValue( + public IDisposable? SetValue( AvaloniaProperty property, object? value, BindingPriority priority = BindingPriority.LocalValue) { property = property ?? throw new ArgumentNullException(nameof(property)); - property.RouteSetValue(this, value, priority); + return property.RouteSetValue(this, value, priority); } /// @@ -385,6 +386,26 @@ public void SetValue(DirectPropertyBase property, T value) SetDirectValueUnchecked(property, value); } + /// + /// Binds a to an observable. + /// + /// The property. + /// The observable. + /// The priority of the binding. + /// + /// A disposable which can be used to terminate the binding. + /// + public IDisposable Bind( + AvaloniaProperty property, + IObservable source, + BindingPriority priority = BindingPriority.LocalValue) + { + property = property ?? throw new ArgumentNullException(nameof(property)); + source = source ?? throw new ArgumentNullException(nameof(source)); + + return property.RouteBind(this, source.ToBindingValue(), priority); + } + /// /// Binds a to an observable. /// @@ -445,9 +466,8 @@ public IDisposable Bind( /// /// Coerces the specified . /// - /// The type of the property. /// The property. - public void CoerceValue(StyledPropertyBase property) + public void CoerceValue(AvaloniaProperty property) { _values?.CoerceValue(property); } @@ -475,19 +495,19 @@ public void EndBatchUpdate() } /// - void IAvaloniaObject.AddInheritanceChild(IAvaloniaObject child) + internal void AddInheritanceChild(AvaloniaObject child) { - _inheritanceChildren ??= new List(); + _inheritanceChildren ??= new List(); _inheritanceChildren.Add(child); } /// - void IAvaloniaObject.RemoveInheritanceChild(IAvaloniaObject child) + internal void RemoveInheritanceChild(AvaloniaObject child) { _inheritanceChildren?.Remove(child); } - void IAvaloniaObject.InheritedPropertyChanged( + internal void InheritedPropertyChanged( AvaloniaProperty property, Optional oldValue, Optional newValue) @@ -565,14 +585,11 @@ void IValueSink.Completed( /// The old inheritance parent. internal void InheritanceParentChanged( StyledPropertyBase property, - IAvaloniaObject? oldParent) + AvaloniaObject? oldParent) { - var oldValue = oldParent switch - { - AvaloniaObject o => o.GetValueOrInheritedOrDefault(property), - null => property.GetDefaultValue(GetType()), - _ => oldParent.GetValue(property) - }; + var oldValue = oldParent is not null ? + oldParent.GetValueOrInheritedOrDefault(property) : + property.GetDefaultValue(GetType()); var newValue = GetInheritedOrDefault(property); diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs index 51237409bff..134e3b2ac7d 100644 --- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs +++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs @@ -25,7 +25,7 @@ public static IBinding ToBinding(this IObservable source) } /// - /// Gets an observable for a . + /// Gets an observable for an . /// /// The object. /// The property. @@ -44,7 +44,7 @@ public static IBinding ToBinding(this IObservable source) } /// - /// Gets an observable for a . + /// Gets an observable for an . /// /// The object. /// The property type. @@ -64,7 +64,7 @@ public static IObservable GetObservable(this IAvaloniaObject o, AvaloniaPr } /// - /// Gets an observable for a . + /// Gets an observable for an . /// /// The object. /// The property. @@ -85,7 +85,7 @@ public static IObservable GetObservable(this IAvaloniaObject o, AvaloniaPr } /// - /// Gets an observable for a . + /// Gets an observable for an . /// /// The object. /// The property type. @@ -128,7 +128,7 @@ public static IObservable GetPropertyChangedOb } /// - /// Gets a subject for a . + /// Gets a subject for an . /// /// The object. /// The property. @@ -150,7 +150,7 @@ public static IObservable GetPropertyChangedOb } /// - /// Gets a subject for a . + /// Gets a subject for an . /// /// The property type. /// The object. @@ -230,30 +230,7 @@ public static ISubject> GetBindingSubject( } /// - /// Binds a to an observable. - /// - /// The object. - /// The property. - /// The observable. - /// The priority of the binding. - /// - /// A disposable which can be used to terminate the binding. - /// - public static IDisposable Bind( - this IAvaloniaObject target, - AvaloniaProperty property, - IObservable> source, - BindingPriority priority = BindingPriority.LocalValue) - { - target = target ?? throw new ArgumentNullException(nameof(target)); - property = property ?? throw new ArgumentNullException(nameof(property)); - source = source ?? throw new ArgumentNullException(nameof(source)); - - return property.RouteBind(target, source, priority); - } - - /// - /// Binds a to an observable. + /// Binds an to an observable. /// /// The type of the property. /// The object. @@ -273,42 +250,22 @@ public static IDisposable Bind( property = property ?? throw new ArgumentNullException(nameof(property)); source = source ?? throw new ArgumentNullException(nameof(source)); - return property switch + if (target is AvaloniaObject ao) { - StyledPropertyBase styled => target.Bind(styled, source, priority), - DirectPropertyBase direct => target.Bind(direct, source), - _ => throw new NotSupportedException("Unsupported AvaloniaProperty type."), - }; - } + return property switch + { + StyledPropertyBase styled => ao.Bind(styled, source, priority), + DirectPropertyBase direct => ao.Bind(direct, source), + _ => throw new NotSupportedException("Unsupported AvaloniaProperty type."), + }; + } - /// - /// Binds a to an observable. - /// - /// The object. - /// The property. - /// The observable. - /// The priority of the binding. - /// - /// A disposable which can be used to terminate the binding. - /// - public static IDisposable Bind( - this IAvaloniaObject target, - AvaloniaProperty property, - IObservable source, - BindingPriority priority = BindingPriority.LocalValue) - { - target = target ?? throw new ArgumentNullException(nameof(target)); - property = property ?? throw new ArgumentNullException(nameof(property)); - source = source ?? throw new ArgumentNullException(nameof(source)); + throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported."); - return target.Bind( - property, - source.ToBindingValue(), - priority); } /// - /// Binds a to an observable. + /// Binds an to an observable. /// /// The object. /// The property. @@ -334,7 +291,7 @@ public static IDisposable Bind( } /// - /// Binds a property on an to an . + /// Binds a property on an to an . /// /// The object. /// The property to bind. @@ -374,56 +331,6 @@ public static IDisposable Bind( } } - /// - /// Clears a 's local value. - /// - /// The object. - /// The property. - public static void ClearValue(this IAvaloniaObject target, AvaloniaProperty property) - { - target = target ?? throw new ArgumentNullException(nameof(target)); - property = property ?? throw new ArgumentNullException(nameof(property)); - - property.RouteClearValue(target); - } - - /// - /// Clears a 's local value. - /// - /// The object. - /// The property. - public static void ClearValue(this IAvaloniaObject target, AvaloniaProperty property) - { - target = target ?? throw new ArgumentNullException(nameof(target)); - property = property ?? throw new ArgumentNullException(nameof(property)); - - switch (property) - { - case StyledPropertyBase styled: - target.ClearValue(styled); - break; - case DirectPropertyBase direct: - target.ClearValue(direct); - break; - default: - throw new NotSupportedException("Unsupported AvaloniaProperty type."); - } - } - - /// - /// Gets a value. - /// - /// The object. - /// The property. - /// The value. - public static object? GetValue(this IAvaloniaObject target, AvaloniaProperty property) - { - target = target ?? throw new ArgumentNullException(nameof(target)); - property = property ?? throw new ArgumentNullException(nameof(property)); - - return property.RouteGetValue(target); - } - /// /// Gets a value. /// @@ -436,12 +343,18 @@ public static T GetValue(this IAvaloniaObject target, AvaloniaProperty pro target = target ?? throw new ArgumentNullException(nameof(target)); property = property ?? throw new ArgumentNullException(nameof(property)); - return property switch + if (target is AvaloniaObject ao) { - StyledPropertyBase styled => target.GetValue(styled), - DirectPropertyBase direct => target.GetValue(direct), - _ => throw new NotSupportedException("Unsupported AvaloniaProperty type.") - }; + return property switch + { + StyledPropertyBase styled => ao.GetValue(styled), + DirectPropertyBase direct => ao.GetValue(direct), + _ => throw new NotSupportedException("Unsupported AvaloniaProperty type.") + }; + + } + + throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported."); } /// @@ -456,7 +369,7 @@ public static T GetValue(this IAvaloniaObject target, AvaloniaProperty pro /// . Note that this method does not return /// property values that come from inherited or default values. /// - /// For direct properties returns . + /// For direct properties returns the current value of the property. /// public static object? GetBaseValue( this IAvaloniaObject target, @@ -466,7 +379,9 @@ public static T GetValue(this IAvaloniaObject target, AvaloniaProperty pro target = target ?? throw new ArgumentNullException(nameof(target)); property = property ?? throw new ArgumentNullException(nameof(property)); - return property.RouteGetBaseValue(target, maxPriority); + if (target is AvaloniaObject ao) + return property.RouteGetBaseValue(ao, maxPriority); + throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported."); } /// @@ -481,8 +396,7 @@ public static T GetValue(this IAvaloniaObject target, AvaloniaProperty pro /// . Note that this method does not return property values /// that come from inherited or default values. /// - /// For direct properties returns - /// . + /// For direct properties returns the current value of the property. /// public static Optional GetBaseValue( this IAvaloniaObject target, @@ -492,69 +406,18 @@ public static Optional GetBaseValue( target = target ?? throw new ArgumentNullException(nameof(target)); property = property ?? throw new ArgumentNullException(nameof(property)); - target = target ?? throw new ArgumentNullException(nameof(target)); - property = property ?? throw new ArgumentNullException(nameof(property)); - - return property switch + if (target is AvaloniaObject ao) { - StyledPropertyBase styled => target.GetBaseValue(styled, maxPriority), - DirectPropertyBase direct => target.GetValue(direct), - _ => throw new NotSupportedException("Unsupported AvaloniaProperty type.") - }; - } - - /// - /// Sets a value. - /// - /// The object. - /// The property. - /// The value. - /// The priority of the value. - /// - /// An if setting the property can be undone, otherwise null. - /// - public static IDisposable? SetValue( - this IAvaloniaObject target, - AvaloniaProperty property, - object? value, - BindingPriority priority = BindingPriority.LocalValue) - { - target = target ?? throw new ArgumentNullException(nameof(target)); - property = property ?? throw new ArgumentNullException(nameof(property)); - - return property.RouteSetValue(target, value, priority); - } - - /// - /// Sets a value. - /// - /// The type of the property. - /// The object. - /// The property. - /// The value. - /// The priority of the value. - /// - /// An if setting the property can be undone, otherwise null. - /// - public static IDisposable? SetValue( - this IAvaloniaObject target, - AvaloniaProperty property, - T value, - BindingPriority priority = BindingPriority.LocalValue) - { - target = target ?? throw new ArgumentNullException(nameof(target)); - property = property ?? throw new ArgumentNullException(nameof(property)); + return property switch + { + StyledPropertyBase styled => ao.GetBaseValue(styled, maxPriority), + DirectPropertyBase direct => ao.GetValue(direct), + _ => throw new NotSupportedException("Unsupported AvaloniaProperty type.") + }; - switch (property) - { - case StyledPropertyBase styled: - return target.SetValue(styled, value, priority); - case DirectPropertyBase direct: - target.SetValue(direct, value); - return null; - default: - throw new NotSupportedException("Unsupported AvaloniaProperty type."); } + + throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported."); } /// @@ -622,17 +485,6 @@ public static IDisposable AddClassHandler( return observable.Subscribe(e => SubscribeAdapter(e, handler)); } - /// - /// Gets a description of a property that van be used in observables. - /// - /// The object. - /// The property - /// The description. - private static string GetDescription(IAvaloniaObject o, AvaloniaProperty property) - { - return $"{o.GetType().Name}.{property.Name}"; - } - /// /// Observer method for . diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs index 3d1e898f501..62ca971412e 100644 --- a/src/Avalonia.Base/AvaloniaProperty.cs +++ b/src/Avalonia.Base/AvaloniaProperty.cs @@ -467,20 +467,20 @@ public abstract void Accept(IAvaloniaPropertyVisitor visitor, ref /// Routes an untyped ClearValue call to a typed call. /// /// The object instance. - internal abstract void RouteClearValue(IAvaloniaObject o); + internal abstract void RouteClearValue(AvaloniaObject o); /// /// Routes an untyped GetValue call to a typed call. /// /// The object instance. - internal abstract object? RouteGetValue(IAvaloniaObject o); + internal abstract object? RouteGetValue(AvaloniaObject o); /// /// Routes an untyped GetBaseValue call to a typed call. /// /// The object instance. /// The maximum priority for the value. - internal abstract object? RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority); + internal abstract object? RouteGetBaseValue(AvaloniaObject o, BindingPriority maxPriority); /// /// Routes an untyped SetValue call to a typed call. @@ -492,7 +492,7 @@ public abstract void Accept(IAvaloniaPropertyVisitor visitor, ref /// An if setting the property can be undone, otherwise null. /// internal abstract IDisposable? RouteSetValue( - IAvaloniaObject o, + AvaloniaObject o, object? value, BindingPriority priority); @@ -503,11 +503,11 @@ public abstract void Accept(IAvaloniaPropertyVisitor visitor, ref /// The binding source. /// The priority. internal abstract IDisposable RouteBind( - IAvaloniaObject o, + AvaloniaObject o, IObservable> source, BindingPriority priority); - internal abstract void RouteInheritanceParentChanged(AvaloniaObject o, IAvaloniaObject? oldParent); + internal abstract void RouteInheritanceParentChanged(AvaloniaObject o, AvaloniaObject? oldParent); /// /// Overrides the metadata for the property on the specified type. diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs index 9c4896b96c4..6e3baea99b7 100644 --- a/src/Avalonia.Base/DirectPropertyBase.cs +++ b/src/Avalonia.Base/DirectPropertyBase.cs @@ -127,25 +127,25 @@ public override void Accept(IAvaloniaPropertyVisitor visitor, ref } /// - internal override void RouteClearValue(IAvaloniaObject o) + internal override void RouteClearValue(AvaloniaObject o) { o.ClearValue(this); } /// - internal override object? RouteGetValue(IAvaloniaObject o) + internal override object? RouteGetValue(AvaloniaObject o) { return o.GetValue(this); } - internal override object? RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority) + internal override object? RouteGetBaseValue(AvaloniaObject o, BindingPriority maxPriority) { return o.GetValue(this); } /// internal override IDisposable? RouteSetValue( - IAvaloniaObject o, + AvaloniaObject o, object? value, BindingPriority priority) { @@ -169,7 +169,7 @@ internal override void RouteClearValue(IAvaloniaObject o) /// internal override IDisposable RouteBind( - IAvaloniaObject o, + AvaloniaObject o, IObservable> source, BindingPriority priority) { @@ -177,7 +177,7 @@ internal override IDisposable RouteBind( return o.Bind(this, adapter); } - internal override void RouteInheritanceParentChanged(AvaloniaObject o, IAvaloniaObject? oldParent) + internal override void RouteInheritanceParentChanged(AvaloniaObject o, AvaloniaObject? oldParent) { throw new NotSupportedException("Direct properties do not support inheritance."); } diff --git a/src/Avalonia.Base/IAvaloniaObject.cs b/src/Avalonia.Base/IAvaloniaObject.cs index 654528658fb..00f5062f9e5 100644 --- a/src/Avalonia.Base/IAvaloniaObject.cs +++ b/src/Avalonia.Base/IAvaloniaObject.cs @@ -17,42 +17,14 @@ public interface IAvaloniaObject /// Clears an 's local value. /// /// The property. - void ClearValue(StyledPropertyBase property); - - /// - /// Clears an 's local value. - /// - /// The property. - void ClearValue(DirectPropertyBase property); - - /// - /// Gets a value. - /// - /// The type of the property. - /// The property. - /// The value. - T GetValue(StyledPropertyBase property); + void ClearValue(AvaloniaProperty property); /// /// Gets a value. /// - /// The type of the property. /// The property. /// The value. - T GetValue(DirectPropertyBase property); - - /// - /// Gets an base value. - /// - /// The type of the property. - /// The property. - /// The maximum priority for the value. - /// - /// Gets the value of the property, if set on this object with a priority equal or lower to - /// , otherwise . Note that - /// this method does not return property values that come from inherited or default values. - /// - Optional GetBaseValue(StyledPropertyBase property, BindingPriority maxPriority); + object? GetValue(AvaloniaProperty property); /// /// Checks whether a is animating. @@ -71,93 +43,35 @@ public interface IAvaloniaObject /// /// Sets a value. /// - /// The type of the property. /// The property. /// The value. /// The priority of the value. /// /// An if setting the property can be undone, otherwise null. /// - IDisposable? SetValue( - StyledPropertyBase property, - T value, + IDisposable? SetValue( + AvaloniaProperty property, + object? value, BindingPriority priority = BindingPriority.LocalValue); - /// - /// Sets a value. - /// - /// The type of the property. - /// The property. - /// The value. - void SetValue(DirectPropertyBase property, T value); - /// /// Binds a to an observable. /// - /// The type of the property. /// The property. /// The observable. /// The priority of the binding. /// /// A disposable which can be used to terminate the binding. /// - IDisposable Bind( - StyledPropertyBase property, - IObservable> source, + IDisposable Bind( + AvaloniaProperty property, + IObservable source, BindingPriority priority = BindingPriority.LocalValue); - /// - /// Binds a to an observable. - /// - /// The type of the property. - /// The property. - /// The observable. - /// - /// A disposable which can be used to terminate the binding. - /// - IDisposable Bind( - DirectPropertyBase property, - IObservable> source); - /// /// Coerces the specified . /// - /// The type of the property. /// The property. - void CoerceValue(StyledPropertyBase property); - - /// - /// Registers an object as an inheritance child. - /// - /// The inheritance child. - /// - /// Inheritance children will receive a call to - /// - /// when an inheritable property value changes on the parent. - /// - void AddInheritanceChild(IAvaloniaObject child); - - /// - /// Unregisters an object as an inheritance child. - /// - /// The inheritance child. - /// - /// Removes an inheritance child that was added by a call to - /// . - /// - void RemoveInheritanceChild(IAvaloniaObject child); - - /// - /// Called when an inheritable property changes on an object registered as an inheritance - /// parent. - /// - /// The type of the value. - /// The property that has changed. - /// - /// - void InheritedPropertyChanged( - AvaloniaProperty property, - Optional oldValue, - Optional newValue); + void CoerceValue(AvaloniaProperty property); } } diff --git a/src/Avalonia.Base/PropertyStore/PriorityValue.cs b/src/Avalonia.Base/PropertyStore/PriorityValue.cs index f670160e75b..03c83d00eda 100644 --- a/src/Avalonia.Base/PropertyStore/PriorityValue.cs +++ b/src/Avalonia.Base/PropertyStore/PriorityValue.cs @@ -1,10 +1,17 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using Avalonia.Data; namespace Avalonia.PropertyStore { + /// + /// Represents an untyped interface to . + /// + interface IPriorityValue : IValue + { + void UpdateEffectiveValue(); + } + /// /// Stores a set of prioritized values and bindings in a . /// @@ -16,7 +23,7 @@ namespace Avalonia.PropertyStore /// entries (sorted first by priority and then in the order /// they were added) plus a local value. /// - internal class PriorityValue : IValue, IValueSink, IBatchUpdate + internal class PriorityValue : IPriorityValue, IValue, IValueSink, IBatchUpdate { private readonly IAvaloniaObject _owner; private readonly IValueSink _sink; diff --git a/src/Avalonia.Base/Reactive/AvaloniaPropertyBindingObservable.cs b/src/Avalonia.Base/Reactive/AvaloniaPropertyBindingObservable.cs index 238bb16e3eb..9f038214c4e 100644 --- a/src/Avalonia.Base/Reactive/AvaloniaPropertyBindingObservable.cs +++ b/src/Avalonia.Base/Reactive/AvaloniaPropertyBindingObservable.cs @@ -51,7 +51,7 @@ private void PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) { if (e is AvaloniaPropertyChangedEventArgs typedArgs) { - var newValue = e.Sender.GetValue(typedArgs.Property); + var newValue = e.Sender.GetValue(typedArgs.Property); if (!_value.HasValue || !EqualityComparer.Default.Equals(newValue, _value.Value)) { diff --git a/src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs b/src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs index fbc126bb059..cafce58c9ce 100644 --- a/src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs +++ b/src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs @@ -49,23 +49,31 @@ private void PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) { if (e.Property == _property) { - T newValue; - - if (e is AvaloniaPropertyChangedEventArgs typed) + if (e.Sender is AvaloniaObject ao) { - newValue = typed.Sender.GetValue(typed.Property); + T newValue; + + if (e is AvaloniaPropertyChangedEventArgs typed) + { + newValue = AvaloniaObjectExtensions.GetValue(ao, typed.Property); + } + else + { + newValue = (T)e.Sender.GetValue(e.Property)!; + } + + if (!_value.HasValue || + !EqualityComparer.Default.Equals(newValue, _value.Value)) + { + _value = newValue; + PublishNext(_value.Value!); + } } else { - newValue = (T)e.Sender.GetValue(e.Property)!; + throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported."); } - if (!_value.HasValue || - !EqualityComparer.Default.Equals(newValue, _value.Value)) - { - _value = newValue; - PublishNext(_value.Value!); - } } } } diff --git a/src/Avalonia.Base/StyledPropertyBase.cs b/src/Avalonia.Base/StyledPropertyBase.cs index 535a826c1e2..f94723866a7 100644 --- a/src/Avalonia.Base/StyledPropertyBase.cs +++ b/src/Avalonia.Base/StyledPropertyBase.cs @@ -177,19 +177,19 @@ public override string ToString() object? IStyledPropertyAccessor.GetDefaultValue(Type type) => GetDefaultBoxedValue(type); /// - internal override void RouteClearValue(IAvaloniaObject o) + internal override void RouteClearValue(AvaloniaObject o) { o.ClearValue(this); } /// - internal override object? RouteGetValue(IAvaloniaObject o) + internal override object? RouteGetValue(AvaloniaObject o) { return o.GetValue(this); } /// - internal override object? RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority) + internal override object? RouteGetBaseValue(AvaloniaObject o, BindingPriority maxPriority) { var value = o.GetBaseValue(this, maxPriority); return value.HasValue ? value.Value : AvaloniaProperty.UnsetValue; @@ -197,7 +197,7 @@ internal override void RouteClearValue(IAvaloniaObject o) /// internal override IDisposable? RouteSetValue( - IAvaloniaObject o, + AvaloniaObject o, object? value, BindingPriority priority) { @@ -221,7 +221,7 @@ internal override void RouteClearValue(IAvaloniaObject o) /// internal override IDisposable RouteBind( - IAvaloniaObject o, + AvaloniaObject o, IObservable> source, BindingPriority priority) { @@ -232,7 +232,7 @@ internal override IDisposable RouteBind( /// internal override void RouteInheritanceParentChanged( AvaloniaObject o, - IAvaloniaObject? oldParent) + AvaloniaObject? oldParent) { o.InheritanceParentChanged(this, oldParent); } diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs index 6b7b5980863..67149b0988e 100644 --- a/src/Avalonia.Base/ValueStore.cs +++ b/src/Avalonia.Base/ValueStore.cs @@ -196,11 +196,11 @@ public void ClearLocalValue(StyledPropertyBase property) } } - public void CoerceValue(StyledPropertyBase property) + public void CoerceValue(AvaloniaProperty property) { if (TryGetValue(property, out var slot)) { - if (slot is PriorityValue p) + if (slot is IPriorityValue p) { p.UpdateEffectiveValue(); } diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs index 353f12118f5..fb047d93dfb 100644 --- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs +++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs @@ -69,15 +69,18 @@ protected override Size MeasureOverride(Size availableSize) { foreach (var child in Children) { - var info = child.GetValue(s_adornedElementInfoProperty); - - if (info != null && info.Bounds.HasValue) - { - child.Measure(info.Bounds.Value.Bounds.Size); - } - else + if (child is AvaloniaObject ao) { - child.Measure(availableSize); + var info = ao.GetValue(s_adornedElementInfoProperty); + + if (info != null && info.Bounds.HasValue) + { + child.Measure(info.Bounds.Value.Bounds.Size); + } + else + { + child.Measure(availableSize); + } } } @@ -88,19 +91,22 @@ protected override Size ArrangeOverride(Size finalSize) { foreach (var child in Children) { - var info = child.GetValue(s_adornedElementInfoProperty); - var isClipEnabled = child.GetValue(IsClipEnabledProperty); - - if (info != null && info.Bounds.HasValue) - { - child.RenderTransform = new MatrixTransform(info.Bounds.Value.Transform); - child.RenderTransformOrigin = new RelativePoint(new Point(0,0), RelativeUnit.Absolute); - UpdateClip(child, info.Bounds.Value, isClipEnabled); - child.Arrange(info.Bounds.Value.Bounds); - } - else + if (child is AvaloniaObject ao) { - child.Arrange(new Rect(finalSize)); + var info = ao.GetValue(s_adornedElementInfoProperty); + var isClipEnabled = ao.GetValue(IsClipEnabledProperty); + + if (info != null && info.Bounds.HasValue) + { + child.RenderTransform = new MatrixTransform(info.Bounds.Value.Transform); + child.RenderTransformOrigin = new RelativePoint(new Point(0, 0), RelativeUnit.Absolute); + UpdateClip(child, info.Bounds.Value, isClipEnabled); + child.Arrange(info.Bounds.Value.Bounds); + } + else + { + child.Arrange(new Rect(finalSize)); + } } } diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index cec02c7ae9e..8714fff71b3 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -533,9 +533,9 @@ protected override void OnTextInput(TextInputEventArgs e) bool Match(ItemContainerInfo info) { - if (info.ContainerControl.IsSet(TextSearch.TextProperty)) + if (info.ContainerControl is AvaloniaObject ao && ao.IsSet(TextSearch.TextProperty)) { - var searchText = info.ContainerControl.GetValue(TextSearch.TextProperty); + var searchText = ao.GetValue(TextSearch.TextProperty); if (searchText?.StartsWith(_textSearchTerm, StringComparison.OrdinalIgnoreCase) == true) { diff --git a/src/Avalonia.Controls/Repeater/ItemsRepeater.cs b/src/Avalonia.Controls/Repeater/ItemsRepeater.cs index 09c0e583327..0260e1999c0 100644 --- a/src/Avalonia.Controls/Repeater/ItemsRepeater.cs +++ b/src/Avalonia.Controls/Repeater/ItemsRepeater.cs @@ -257,10 +257,9 @@ bool IChildIndexProvider.TryGetTotalCount(out int count) internal void UnpinElement(IControl element) => _viewManager.UpdatePin(element, false); - internal static VirtualizationInfo TryGetVirtualizationInfo(IControl element) + internal static VirtualizationInfo? TryGetVirtualizationInfo(IControl element) { - var value = element.GetValue(VirtualizationInfoProperty); - return value; + return (element as AvaloniaObject)?.GetValue(VirtualizationInfoProperty); } internal static VirtualizationInfo CreateAndInitializeVirtualizationInfo(IControl element) @@ -277,15 +276,20 @@ internal static VirtualizationInfo CreateAndInitializeVirtualizationInfo(IContro internal static VirtualizationInfo GetVirtualizationInfo(IControl element) { - var result = element.GetValue(VirtualizationInfoProperty); - - if (result == null) + if (element is AvaloniaObject ao) { - result = new VirtualizationInfo(); - element.SetValue(VirtualizationInfoProperty, result); + var result = ao.GetValue(VirtualizationInfoProperty); + + if (result == null) + { + result = new VirtualizationInfo(); + ao.SetValue(VirtualizationInfoProperty, result); + } + + return result; } - return result; + throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported."); } private protected override void InvalidateMeasureOnChildrenChanged() @@ -491,7 +495,7 @@ private int GetElementIndexImpl(IControl element) if (parent == this) { var virtInfo = TryGetVirtualizationInfo(element); - return _viewManager.GetElementIndex(virtInfo); + return _viewManager.GetElementIndex(virtInfo!); } return -1; diff --git a/src/Avalonia.Controls/Repeater/RecyclePool.cs b/src/Avalonia.Controls/Repeater/RecyclePool.cs index 9e2da81f991..cf2b40836ed 100644 --- a/src/Avalonia.Controls/Repeater/RecyclePool.cs +++ b/src/Avalonia.Controls/Repeater/RecyclePool.cs @@ -80,8 +80,8 @@ public void PutElement(IControl element, string key, IControl? owner) return null; } - internal string GetReuseKey(IControl element) => element.GetValue(ReuseKeyProperty); - internal void SetReuseKey(IControl element, string value) => element.SetValue(ReuseKeyProperty, value); + internal string GetReuseKey(IControl element) => ((Control)element).GetValue(ReuseKeyProperty); + internal void SetReuseKey(IControl element, string value) => ((Control)element).SetValue(ReuseKeyProperty, value); private IPanel? EnsureOwnerIsPanelOrNull(IControl? owner) { diff --git a/src/Avalonia.Controls/Repeater/ViewManager.cs b/src/Avalonia.Controls/Repeater/ViewManager.cs index b28753b5189..12db48a2c25 100644 --- a/src/Avalonia.Controls/Repeater/ViewManager.cs +++ b/src/Avalonia.Controls/Repeater/ViewManager.cs @@ -47,7 +47,7 @@ public IControl GetElement(int index, bool forceCreate, bool suppressAutoRecycle if (madeAnchor != null) { var anchorVirtInfo = ItemsRepeater.TryGetVirtualizationInfo(madeAnchor); - if (anchorVirtInfo.Index == index) + if (anchorVirtInfo!.Index == index) { element = madeAnchor; } @@ -60,12 +60,12 @@ public IControl GetElement(int index, bool forceCreate, bool suppressAutoRecycle var virtInfo = ItemsRepeater.TryGetVirtualizationInfo(element); if (suppressAutoRecycle) { - virtInfo.AutoRecycleCandidate = false; + virtInfo!.AutoRecycleCandidate = false; Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "GetElement: {Index} Not AutoRecycleCandidate:", virtInfo.Index); } else { - virtInfo.AutoRecycleCandidate = true; + virtInfo!.AutoRecycleCandidate = true; virtInfo.KeepAlive = true; Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "GetElement: {Index} AutoRecycleCandidate:", virtInfo.Index); } diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs index 4dc0c34c0a5..0c0c005122a 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs @@ -110,7 +110,7 @@ public VerticalAlignment VerticalAlignment private void UpdateSizeConstraints() { - if (_control is IAvaloniaObject ao) + if (_control is AvaloniaObject ao) { string? CreateConstraintInfo(StyledProperty minProperty, StyledProperty maxProperty) { @@ -191,7 +191,7 @@ public void ControlPropertyChanged(object? sender, AvaloniaPropertyChangedEventA } else { - if (_control is IAvaloniaObject ao) + if (_control is AvaloniaObject ao) { if (e.Property == Layoutable.MarginProperty) { diff --git a/src/Avalonia.Input/KeyboardNavigation.cs b/src/Avalonia.Input/KeyboardNavigation.cs index a25aed6811a..042a9adf5fb 100644 --- a/src/Avalonia.Input/KeyboardNavigation.cs +++ b/src/Avalonia.Input/KeyboardNavigation.cs @@ -58,7 +58,7 @@ public static class KeyboardNavigation /// The for the container. public static int GetTabIndex(IInputElement element) { - return ((IAvaloniaObject)element).GetValue(TabIndexProperty); + return ((AvaloniaObject)element).GetValue(TabIndexProperty); } /// diff --git a/src/Avalonia.Input/Navigation/TabNavigation.cs b/src/Avalonia.Input/Navigation/TabNavigation.cs index c8290cb3b79..cfd45f82628 100644 --- a/src/Avalonia.Input/Navigation/TabNavigation.cs +++ b/src/Avalonia.Input/Navigation/TabNavigation.cs @@ -610,7 +610,7 @@ internal static class TabNavigation private static IInputElement? GetActiveElement(IInputElement e) { - return ((IAvaloniaObject)e).GetValue(KeyboardNavigation.TabOnceActiveElementProperty); + return ((AvaloniaObject)e).GetValue(KeyboardNavigation.TabOnceActiveElementProperty); } private static IInputElement GetGroupParent(IInputElement e) => GetGroupParent(e, false); @@ -655,8 +655,9 @@ private static IInputElement GetGroupParent(IInputElement element, bool includeC private static KeyboardNavigationMode GetKeyNavigationMode(IInputElement e) { - return ((IAvaloniaObject)e).GetValue(KeyboardNavigation.TabNavigationProperty); + return ((AvaloniaObject)e).GetValue(KeyboardNavigation.TabNavigationProperty); } + private static bool IsFocusScope(IInputElement e) => FocusManager.GetIsFocusScope(e) || GetParent(e) == null; private static bool IsGroup(IInputElement e) => GetKeyNavigationMode(e) != KeyboardNavigationMode.Continue; diff --git a/src/Avalonia.Styling/StyledElement.cs b/src/Avalonia.Styling/StyledElement.cs index 5f498623e15..f98d2cdbccb 100644 --- a/src/Avalonia.Styling/StyledElement.cs +++ b/src/Avalonia.Styling/StyledElement.cs @@ -467,7 +467,12 @@ void ISetLogicalParent.SetParent(ILogical? parent) /// The parent. void ISetInheritanceParent.SetParent(IAvaloniaObject? parent) { - InheritanceParent = parent; + InheritanceParent = parent switch + { + AvaloniaObject ao => ao, + null => null, + _ => throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.") + }; } void IStyleable.StyleApplied(IStyleInstance instance) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index 99072ace028..0adfa71ee77 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -135,7 +135,7 @@ public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg) NameScopeSetNameScope = NameScope.GetMethod(new FindMethodMethodSignature("SetNameScope", XamlIlTypes.Void, StyledElement, INameScope) { IsStatic = true }); - AvaloniaObjectSetValueMethod = AvaloniaObject.FindMethod("SetValue", XamlIlTypes.Void, + AvaloniaObjectSetValueMethod = AvaloniaObject.FindMethod("SetValue", IDisposable, false, AvaloniaProperty, XamlIlTypes.Object, BindingPriority); IPropertyInfo = cfg.TypeSystem.GetType("Avalonia.Data.Core.IPropertyInfo"); ClrPropertyInfo = cfg.TypeSystem.GetType("Avalonia.Data.Core.ClrPropertyInfo"); diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs index 1adb6988a28..ee29c823458 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs @@ -152,35 +152,35 @@ public override void Accept(IAvaloniaPropertyVisitor vistor, ref T } internal override IDisposable RouteBind( - IAvaloniaObject o, + AvaloniaObject o, IObservable> source, BindingPriority priority) { throw new NotImplementedException(); } - internal override void RouteClearValue(IAvaloniaObject o) + internal override void RouteClearValue(AvaloniaObject o) { throw new NotImplementedException(); } - internal override object RouteGetValue(IAvaloniaObject o) + internal override object RouteGetValue(AvaloniaObject o) { throw new NotImplementedException(); } - internal override object RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority) + internal override object RouteGetBaseValue(AvaloniaObject o, BindingPriority maxPriority) { throw new NotImplementedException(); } - internal override void RouteInheritanceParentChanged(AvaloniaObject o, IAvaloniaObject oldParent) + internal override void RouteInheritanceParentChanged(AvaloniaObject o, AvaloniaObject oldParent) { throw new NotImplementedException(); } internal override IDisposable RouteSetValue( - IAvaloniaObject o, + AvaloniaObject o, object value, BindingPriority priority) { diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_TemplatedParent.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_TemplatedParent.cs index 37721badb08..f04b95aaff1 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_TemplatedParent.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_TemplatedParent.cs @@ -1,16 +1,11 @@ -using System; +using System.Linq; using System.Reactive.Linq; -using System.Reactive.Subjects; -using Moq; using Avalonia.Controls; +using Avalonia.Controls.Presenters; +using Avalonia.Controls.Templates; using Avalonia.Data; -using Avalonia.Styling; -using Xunit; -using System.Reactive.Disposables; -using Avalonia.UnitTests; using Avalonia.VisualTree; -using System.Linq; -using Avalonia.Markup.Data; +using Xunit; namespace Avalonia.Markup.UnitTests.Data { @@ -19,53 +14,57 @@ public class BindingTests_TemplatedParent [Fact] public void OneWay_Binding_Should_Be_Set_Up() { - var target = CreateTarget(); - var binding = new Binding + var source = new Button { - Mode = BindingMode.OneWay, - RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent), - Priority = BindingPriority.TemplatedParent, - Path = "Foo", + Template = new FuncControlTemplate