Files
HandyControl/src/Shared/HandyControl_Shared/Controls/Panel/ElementGroup.cs
T

154 lines
6.2 KiB
C#

using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using HandyControl.Data;
using HandyControl.Tools;
namespace HandyControl.Controls
{
public class ElementGroup : ItemsControl
{
private static readonly Dictionary<Orientation, Dictionary<ChildLocation, CornerRadius>> CornerRadiusDict;
public static readonly DependencyProperty OrientationProperty =
StackPanel.OrientationProperty.AddOwner(typeof(ElementGroup),
new FrameworkPropertyMetadata(ValueBoxes.HorizontalBox, FrameworkPropertyMetadataOptions.AffectsMeasure));
public Orientation Orientation
{
get => (Orientation) GetValue(OrientationProperty);
set => SetValue(OrientationProperty, ValueBoxes.OrientationBox(value));
}
public static readonly DependencyProperty LayoutProperty = DependencyProperty.Register(
"Layout", typeof(LinearLayout), typeof(ElementGroup),
new FrameworkPropertyMetadata(LinearLayout.Uniform, FrameworkPropertyMetadataOptions.AffectsMeasure));
public LinearLayout Layout
{
get => (LinearLayout) GetValue(LayoutProperty);
set => SetValue(LayoutProperty, value);
}
static ElementGroup()
{
var defaultCornerRadius = ResourceHelper.GetResourceInternal<CornerRadius>("DefaultCornerRadius");
CornerRadiusDict = new Dictionary<Orientation, Dictionary<ChildLocation, CornerRadius>>
{
[Orientation.Horizontal] = new()
{
[ChildLocation.Single] = defaultCornerRadius,
[ChildLocation.First] = new CornerRadius(defaultCornerRadius.TopLeft, 0, 0, defaultCornerRadius.BottomLeft),
[ChildLocation.Middle] = new CornerRadius(),
[ChildLocation.Last] = new CornerRadius(0, defaultCornerRadius.TopRight, defaultCornerRadius.BottomRight, 0)
},
[Orientation.Vertical] = new()
{
[ChildLocation.Single] = defaultCornerRadius,
[ChildLocation.First] = new CornerRadius(defaultCornerRadius.TopLeft, defaultCornerRadius.TopRight, 0, 0),
[ChildLocation.Middle] = new CornerRadius(),
[ChildLocation.Last] = new CornerRadius(0, 0, defaultCornerRadius.BottomRight, defaultCornerRadius.BottomLeft)
}
};
}
protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
{
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
if (visualAdded is UIElement elementAdded)
{
elementAdded.GotFocus += ElementAdded_GotFocus;
elementAdded.LostFocus += ElementAdded_LostFocus;
elementAdded.IsVisibleChanged += ElementAdded_IsVisibleChanged;
}
if (visualRemoved is UIElement elementRemoved)
{
elementRemoved.GotFocus -= ElementAdded_GotFocus;
elementRemoved.LostFocus -= ElementAdded_LostFocus;
elementRemoved.IsVisibleChanged -= ElementAdded_IsVisibleChanged;
}
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) => UpdateChildrenCornerRadius();
protected override void OnRender(DrawingContext drawingContext) => UpdateChildrenCornerRadius();
private void UpdateChildrenCornerRadius()
{
var visibleChildren = GetVisibleChildrenCount();
var count = visibleChildren.Count;
if (count == 0)
{
return;
}
var orientation = Orientation;
if (count == 1)
{
UpdateChildCornerRadius(visibleChildren[0], CornerRadiusDict[orientation][ChildLocation.Single]);
}
else
{
UpdateChildCornerRadius(visibleChildren[0], CornerRadiusDict[orientation][ChildLocation.First]);
var childMargin = orientation == Orientation.Horizontal
? new Thickness(-1, 0, 0, 0)
: new Thickness(0, -1, 0, 0);
for (var childIndex = 1; childIndex < count; childIndex++)
{
var child = visibleChildren[childIndex];
child.SetCurrentValue(MarginProperty, childMargin);
UpdateChildCornerRadius(child, CornerRadiusDict[orientation][ChildLocation.Middle]);
}
var lastChild = visibleChildren[count - 1];
lastChild.SetCurrentValue(MarginProperty, childMargin);
UpdateChildCornerRadius(lastChild, CornerRadiusDict[orientation][ChildLocation.Last]);
}
}
private List<UIElement> GetVisibleChildrenCount()
{
return Items.OfType<UIElement>().Where(element => element.Visibility == Visibility.Visible).ToList();
}
private static void UpdateChildCornerRadius(DependencyObject child, CornerRadius cornerRadius)
{
if (child is Border border)
{
border.SetCurrentValue(Border.CornerRadiusProperty, cornerRadius);
}
else
{
BorderElement.SetCornerRadius(child, cornerRadius);
}
}
private void ElementAdded_LostFocus(object sender, RoutedEventArgs e) => ResetElementZIndex(e.OriginalSource);
private void ElementAdded_GotFocus(object sender, RoutedEventArgs e) => MaximizeElementZIndex(e.OriginalSource);
private static void ResetElementZIndex(object element) => Panel.SetZIndex((UIElement) element, 0);
private static void MaximizeElementZIndex(object element) => Panel.SetZIndex((UIElement) element, int.MaxValue);
private void ElementAdded_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) => UpdateChildrenCornerRadius();
private enum ChildLocation
{
Single,
First,
Middle,
Last
}
}
}