using System; using Avalonia.Data; using Avalonia.Reactive; using Avalonia.Styling; namespace Avalonia { /// /// Base class for direct properties. /// /// The type of the property's value. /// /// Whereas is typed on the owner type, this base /// class provides a non-owner-typed interface to a direct property. /// public abstract class DirectPropertyBase : AvaloniaProperty { /// /// Initializes a new instance of the class. /// /// The name of the property. /// The type of the class that registers the property. /// The property metadata. protected DirectPropertyBase( string name, Type ownerType, AvaloniaPropertyMetadata metadata) : base(name, ownerType, metadata) { } /// /// Initializes a new instance of the class. /// /// The property to copy. /// The new owner type. /// Optional overridden metadata. [Obsolete("Use constructor with DirectPropertyBase instead.", true)] protected DirectPropertyBase( AvaloniaProperty source, Type ownerType, AvaloniaPropertyMetadata metadata) : this(source as DirectPropertyBase ?? throw new InvalidOperationException(), ownerType, metadata) { } /// /// Initializes a new instance of the class. /// /// The property to copy. /// The new owner type. /// Optional overridden metadata. protected DirectPropertyBase( DirectPropertyBase source, Type ownerType, AvaloniaPropertyMetadata metadata) : base(source, ownerType, metadata) { } /// /// Gets the type that registered the property. /// public abstract Type Owner { get; } /// /// Gets the value of the property on the instance. /// /// The instance. /// The property value. internal abstract TValue InvokeGetter(IAvaloniaObject instance); /// /// Sets the value of the property on the instance. /// /// The instance. /// The value. internal abstract void InvokeSetter(IAvaloniaObject instance, BindingValue value); /// /// Gets the unset value for the property on the specified type. /// /// The type. /// The unset value. public TValue GetUnsetValue(Type type) { type = type ?? throw new ArgumentNullException(nameof(type)); return GetMetadata(type).UnsetValue; } /// /// Gets the property metadata for the specified type. /// /// The type. /// /// The property metadata. /// public new DirectPropertyMetadata GetMetadata(Type type) { return (DirectPropertyMetadata)base.GetMetadata(type); } /// /// Overrides the metadata for the property on the specified type. /// /// The type. /// The metadata. public void OverrideMetadata(DirectPropertyMetadata metadata) where T : IAvaloniaObject { base.OverrideMetadata(typeof(T), metadata); } /// /// Overrides the metadata for the property on the specified type. /// /// The type. /// The metadata. public void OverrideMetadata(Type type, DirectPropertyMetadata metadata) { base.OverrideMetadata(type, metadata); } /// internal override void RouteClearValue(AvaloniaObject o) { o.ClearValue(this); } /// internal override object? RouteGetValue(AvaloniaObject o) { return o.GetValue(this); } internal override object? RouteGetBaseValue(AvaloniaObject o, BindingPriority maxPriority) { return o.GetValue(this); } /// internal override IDisposable? RouteSetValue( AvaloniaObject o, object? value, BindingPriority priority) { var v = TryConvert(value); if (v.HasValue) { o.SetValue(this, (TValue)v.Value!); } else if (v.Type == BindingValueType.UnsetValue) { o.ClearValue(this); } else if (v.HasError) { throw v.Error!; } return null; } /// internal override IDisposable RouteBind( AvaloniaObject o, IObservable> source, BindingPriority priority) { var adapter = TypedBindingAdapter.Create(o, this, source); return o.Bind(this, adapter); } internal override void RouteInheritanceParentChanged(AvaloniaObject o, AvaloniaObject? oldParent) { throw new NotSupportedException("Direct properties do not support inheritance."); } internal override ISetterInstance CreateSetterInstance(IStyleable target, object? value) { if (value is IBinding binding) { return new PropertySetterBindingInstance( target, this, binding); } else if (value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(PropertyType)) { return new PropertySetterTemplateInstance( target, this, template); } else { return new PropertySetterInstance( target, this, (TValue)value!); } } } }