using System; using System.Diagnostics.CodeAnalysis; using Avalonia.Data; namespace Avalonia { /// /// A direct avalonia property. /// /// The class that registered the property. /// The type of the property's value. /// /// Direct avalonia properties are backed by a field on the object, but exposed via the /// system. They hold a getter and an optional setter which /// allows the avalonia property system to read and write the current value. /// public class DirectProperty : DirectPropertyBase, IDirectPropertyAccessor where TOwner : IAvaloniaObject { /// /// Initializes a new instance of the class. /// /// The name of the property. /// Gets the current value of the property. /// Sets the value of the property. May be null. /// The property metadata. public DirectProperty( string name, Func getter, Action? setter, DirectPropertyMetadata metadata) : base(name, typeof(TOwner), metadata) { Getter = getter ?? throw new ArgumentNullException(nameof(getter)); Setter = setter; } /// /// Initializes a new instance of the class. /// /// The property to copy. /// Gets the current value of the property. /// Sets the value of the property. May be null. /// Optional overridden metadata. private DirectProperty( DirectPropertyBase source, Func getter, Action? setter, DirectPropertyMetadata metadata) : base(source, typeof(TOwner), metadata) { Getter = getter ?? throw new ArgumentNullException(nameof(getter)); Setter = setter; } /// public override bool IsDirect => true; /// public override bool IsReadOnly => Setter == null; /// public override Type Owner => typeof(TOwner); /// /// Gets the getter function. /// public Func Getter { get; } /// /// Gets the setter function. /// public Action? Setter { get; } /// /// Registers the direct property on another type. /// /// The type of the additional owner. /// Gets the current value of the property. /// Sets the value of the property. /// /// The value to use when the property is set to /// /// The default binding mode for the property. /// /// Whether the property is interested in data validation. /// /// The property. public DirectProperty AddOwner( Func getter, Action? setter = null, TValue unsetValue = default!, BindingMode defaultBindingMode = BindingMode.Default, bool enableDataValidation = false) where TNewOwner : AvaloniaObject { var metadata = new DirectPropertyMetadata( unsetValue: unsetValue, defaultBindingMode: defaultBindingMode, enableDataValidation: enableDataValidation); metadata.Merge(GetMetadata(), this); var result = new DirectProperty( (DirectPropertyBase)this, getter, setter, metadata); AvaloniaPropertyRegistry.Instance.Register(typeof(TNewOwner), result); return result; } /// /// Registers the direct property on another type. /// /// The type of the additional owner. /// Gets the current value of the property. /// Sets the value of the property. /// /// The value to use when the property is set to /// /// The default binding mode for the property. /// /// Whether the property is interested in data validation. /// /// The property. public DirectProperty AddOwnerWithDataValidation( Func getter, Action setter, TValue unsetValue = default!, BindingMode defaultBindingMode = BindingMode.Default, bool enableDataValidation = false) where TNewOwner : AvaloniaObject { var metadata = new DirectPropertyMetadata( unsetValue: unsetValue, defaultBindingMode: defaultBindingMode, enableDataValidation: enableDataValidation); metadata.Merge(GetMetadata(), this); var result = new DirectProperty( this, getter, setter, metadata); AvaloniaPropertyRegistry.Instance.Register(typeof(TNewOwner), result); return result; } /// internal override TValue InvokeGetter(IAvaloniaObject instance) { return Getter((TOwner)instance); } /// internal override void InvokeSetter(IAvaloniaObject instance, BindingValue value) { if (Setter == null) { throw new ArgumentException($"The property {Name} is readonly."); } if (value.HasValue) { Setter((TOwner)instance, value.Value); } } /// object? IDirectPropertyAccessor.GetValue(IAvaloniaObject instance) { return Getter((TOwner)instance); } /// void IDirectPropertyAccessor.SetValue(IAvaloniaObject instance, object? value) { if (Setter == null) { throw new ArgumentException($"The property {Name} is readonly."); } Setter((TOwner)instance, (TValue)value!); } } }