using System; using System.Collections.Generic; using System.Linq; namespace Robust.Client.UserInterface { public partial class Control { private Dictionary? _attachedProperties; /// /// Gets the value of an attached property on this control. /// /// The attached property to get the value of. /// /// The property's value for this object, /// or the property's default value if it has not been set on this control yet. /// public object? GetValue(AttachedProperty property) { if (_attachedProperties == null) { return property.DefaultValue; } if (!_attachedProperties.TryGetValue(property, out var value)) { return property.DefaultValue; } return value; } public T GetValue(AttachedProperty property) { if (_attachedProperties == null) { return property.DefaultValue; } if (!_attachedProperties.TryGetValue(property, out var value)) { return property.DefaultValue; } return (T) value!; } /// /// Gets the value of an attached property on this control. /// /// The attached property to get the value of. /// The type to cast the property value to, for convenience. /// /// The property's value for this object, /// or the property's default value if it has not been set on this control yet. /// /// /// Thrown if the property value is not of type /// public T GetValue(AttachedProperty property) { return (T) GetValue(property)!; } /// /// Sets the value of an attached property on this control. /// /// /// If possible, it is recommended to use instead. /// /// The attached property to set. /// The new value. /// /// Thrown if the property type is a non-nullable value type, but is null. /// /// /// Thrown if the type of is not assignable to the property's type. /// /// /// Thrown if the property has a validation function, and the validation function failed. /// public void SetValue(AttachedProperty property, object? value) { if (_attachedProperties == null) { _attachedProperties = new Dictionary(); } // Verify that the value can be assigned to the property. if (value == null) { if (property.PropertyType.IsValueType && // Nullable actually boxes as null. Keep that in mind. Nullable.GetUnderlyingType(property.PropertyType) == null) { throw new ArgumentNullException(nameof(value), "Property is a value type, but null was passed as value."); } } else { if (!property.PropertyType.IsInstanceOfType(value)) { throw new ArgumentException("Value is of wrong type for property.", nameof(value)); } } if (property.Validate != null && !property.Validate(value)) { throw new ArgumentException("Value is not valid for this property.", nameof(value)); } if (!_attachedProperties.TryGetValue(property, out var oldValue)) { oldValue = property.DefaultValue; } var changed = new AttachedPropertyChangedEventArgs(value, oldValue); _attachedProperties[property] = value; property.Changed?.Invoke(this, changed); } public void SetValue(AttachedProperty property, T value) { _attachedProperties ??= new Dictionary(); if (property.Validate != null && !property.Validate(value)) { throw new ArgumentException("Value is not valid for this property.", nameof(value)); } T oldValue; if (!_attachedProperties.TryGetValue(property, out var oldValueBoxed)) { oldValue = property.DefaultValue; } else { oldValue = (T) oldValueBoxed!; } var changed = new AttachedPropertyChangedEventArgs(value, oldValue); _attachedProperties[property] = value; property.Changed?.Invoke(this, changed); } // Using generics simplifies the type check A LOT, so this is preferred. /// /// Sets the value of an attached property on this control. /// /// The attached property to set. /// The new value. /// /// The type of the value being assigned. /// /// /// Thrown if the type of is not assignable to the property's type. /// /// /// Thrown if the property has a validation function, and the validation function failed. /// public void SetValue(AttachedProperty property, T value) { if (_attachedProperties == null) { _attachedProperties = new Dictionary(); } if (!property.PropertyType.IsAssignableFrom(typeof(T))) { throw new InvalidOperationException("Property is of the wrong type."); } if (typeof(T) == typeof(object)) { SetValue(property, (object?) value); return; } if (property.Validate != null && !property.Validate(value)) { throw new ArgumentException("Value is not valid for this property.", nameof(value)); } if (!_attachedProperties.TryGetValue(property, out var oldValue)) { oldValue = property.DefaultValue; } var changed = new AttachedPropertyChangedEventArgs(value, oldValue); _attachedProperties[property] = value; property.Changed?.Invoke(this, changed); } public IEnumerable> AllAttachedProperties => _attachedProperties ?? Enumerable.Empty>(); } }