107 lines
3.4 KiB
C#
107 lines
3.4 KiB
C#
|
|
using WPFluent.Converters;
|
|||
|
|
|
|||
|
|
using System.Windows.Controls;
|
|||
|
|
using System.Windows.Documents;
|
|||
|
|
using System.Windows.Input;
|
|||
|
|
|
|||
|
|
// ReSharper disable once CheckNamespace
|
|||
|
|
namespace WPFluent.Controls;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Represents the base class for an icon UI element.
|
|||
|
|
/// </summary>
|
|||
|
|
[TypeConverter(typeof(IconElementConverter))]
|
|||
|
|
public abstract class IconElement : FrameworkElement
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Identifies the <see cref="Foreground"/> dependency property.
|
|||
|
|
/// </summary>
|
|||
|
|
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;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Coerces the value of an Icon dependency property, allowing the use of either IconElement or IconSourceElement.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="_">The dependency object (unused).</param>
|
|||
|
|
/// <param name="baseValue">The value to be coerced.</param>
|
|||
|
|
/// <returns>An IconElement, either directly or derived from an IconSourceElement.</returns>
|
|||
|
|
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)),
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <inheritdoc cref="Control.Foreground"/>
|
|||
|
|
[Bindable(true)]
|
|||
|
|
[Category("Appearance")]
|
|||
|
|
public Brush Foreground { get => (Brush)GetValue(ForegroundProperty); set => SetValue(ForegroundProperty, value); }
|
|||
|
|
}
|