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!);
}
}
}