using WPFluent.Converters; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; // ReSharper disable once CheckNamespace namespace WPFluent.Controls; /// /// Represents the base class for an icon UI element. /// [TypeConverter(typeof(IconElementConverter))] public abstract class IconElement : FrameworkElement { /// /// Identifies the dependency property. /// public static readonly DependencyProperty ForegroundProperty = TextElement.ForegroundProperty .AddOwner( typeof(IconElement), new FrameworkPropertyMetadata( SystemColors.ControlTextBrush, FrameworkPropertyMetadataOptions.Inherits, static(d, args) => ((IconElement)d).OnForegroundChanged(args))); private Grid? _layoutRoot; static IconElement() { FocusableProperty.OverrideMetadata(typeof(IconElement), new FrameworkPropertyMetadata(false)); KeyboardNavigation.IsTabStopProperty.OverrideMetadata(typeof(IconElement), new FrameworkPropertyMetadata(false)); } private void EnsureLayoutRoot() { if(_layoutRoot != null) { return; } _layoutRoot = new Grid { Background = Brushes.Transparent, SnapsToDevicePixels = true }; _layoutRoot.Children.Add(InitializeChildren()); AddVisualChild(_layoutRoot); } protected override Size ArrangeOverride(Size finalSize) { EnsureLayoutRoot(); _layoutRoot!.Arrange(new Rect(default, finalSize)); return finalSize; } protected override Visual GetVisualChild(int index) { if(index != 0) { throw new ArgumentOutOfRangeException(nameof(index), "IconElement should have only 1 child"); } EnsureLayoutRoot(); return _layoutRoot!; } protected abstract UIElement InitializeChildren(); protected override Size MeasureOverride(Size availableSize) { EnsureLayoutRoot(); _layoutRoot!.Measure(availableSize); return _layoutRoot.DesiredSize; } protected virtual void OnForegroundChanged(DependencyPropertyChangedEventArgs args) { } protected override int VisualChildrenCount => 1; /// /// Coerces the value of an Icon dependency property, allowing the use of either IconElement or IconSourceElement. /// /// The dependency object (unused). /// The value to be coerced. /// An IconElement, either directly or derived from an IconSourceElement. public static object? Coerce(DependencyObject _, object? baseValue) { return baseValue switch { IconSourceElement iconSourceElement => iconSourceElement.CreateIconElement(), IconElement or null => baseValue, _ => throw new ArgumentException( message: $"Expected either '{typeof(IconSourceElement)}' or '{typeof(IconElement)}' but got '{baseValue.GetType()}'.", paramName: nameof(baseValue)), }; } /// [Bindable(true)] [Category("Appearance")] public Brush Foreground { get => (Brush)GetValue(ForegroundProperty); set => SetValue(ForegroundProperty, value); } }