WPF开发者QQ群: 340500857 | 微信群 -> 进入公众号主页 加入组织
由于微信群人数太多入群请添加小编微信号
(yanjinhuawechat)或(W_Feng_aiQ)邀请入群
(需备注WPF开发者)
PS:有更好的方式欢迎推荐。
01
—
代码如下
一、创建 DrawingControl.cs 继承 ListBox代码如下。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;namespace WPFDevelopers.Controls
{[TemplatePart(Name = _PartInnerName, Type = typeof(Border))]//[TemplatePart(Name = _PartDrawingPanelName, Type=typeof(DrawingPanel))]//[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(DrawingElement))]public class DrawingControl : ListBox{static DrawingControl(){DefaultStyleKeyProperty.OverrideMetadata(typeof(DrawingControl), new FrameworkPropertyMetadata(typeof(DrawingControl)));}private const string _PartInnerName = "PART_InnerBorder";//private const string _PartDrawingPanelName = "PART_DrawingPanel";public DrawingControl(){Loaded += DrawingControl_Loaded;SizeChanged += DrawingControl_SizeChanged;}protected DrawingPanel _DrawingPanel = default;protected Border _Border = default;public override void OnApplyTemplate(){base.OnApplyTemplate();_Border = GetTemplateChild(_PartInnerName) as Border;// _DrawingPanel = GetTemplateChild(_PartDrawingPanelName) as DrawingPanel;if (_Border == null)throw new Exception($"The {_PartInnerName} is not exist!");}private void DrawingControl_Loaded(object sender, RoutedEventArgs e){//Width = Math.Min(RenderSize.Width, RenderSize.Height);//Height = Width;}private void DrawingControl_SizeChanged(object sender, SizeChangedEventArgs e){var vMin = Math.Min(e.NewSize.Width, e.NewSize.Height);PanelCornerRadius = new CornerRadius(vMin);InnerCornerRadius = new CornerRadius(vMin);//InnerMargin = new Thickness(vMin * Scale);if (_Border != null){_Border.Width = vMin * Scale;_Border.Height = vMin * Scale;}}public double ItemOffset{get { return (double)GetValue(ItemOffsetProperty); }set { SetValue(ItemOffsetProperty, value); }}public static readonly DependencyProperty ItemOffsetProperty =DependencyProperty.Register("ItemOffset", typeof(double), typeof(DrawingControl), new PropertyMetadata(10d));public Brush PanelBackground{get { return (Brush)GetValue(PanelBackgroundProperty); }set { SetValue(PanelBackgroundProperty, value); }}public static readonly DependencyProperty PanelBackgroundProperty =DependencyProperty.Register("PanelBackground", typeof(Brush), typeof(DrawingControl), new PropertyMetadata(default));public Brush PanelBorderBrush{get { return (Brush)GetValue(PanelBorderBrushProperty); }set { SetValue(PanelBorderBrushProperty, value); }}public static readonly DependencyProperty PanelBorderBrushProperty =DependencyProperty.Register("PanelBorderBrush", typeof(Brush), typeof(DrawingControl), new PropertyMetadata(Brushes.Gray));public Thickness PanelBorderThinckness{get { return (Thickness)GetValue(PanelBorderThincknessProperty); }set { SetValue(PanelBorderThincknessProperty, value); }}public static readonly DependencyProperty PanelBorderThincknessProperty =DependencyProperty.Register("PanelBorderThinckness", typeof(Thickness), typeof(DrawingControl), new PropertyMetadata(new Thickness(1d)));public CornerRadius PanelCornerRadius{get { return (CornerRadius)GetValue(PanelCornerRadiusProperty); }set { SetValue(PanelCornerRadiusProperty, value); }}public static readonly DependencyProperty PanelCornerRadiusProperty =DependencyProperty.Register("PanelCornerRadius", typeof(CornerRadius), typeof(DrawingControl), new PropertyMetadata(new CornerRadius(1d)));public DrawingMode PanelDrawingMode{get { return (DrawingMode)GetValue(PanelDrawingModeProperty); }set { SetValue(PanelDrawingModeProperty, value); }}public static readonly DependencyProperty PanelDrawingModeProperty =DependencyProperty.Register("PanelDrawingMode", typeof(DrawingMode), typeof(DrawingControl), new PropertyMetadata(default(DrawingMode)));public double PanelStartAngleOffset{get { return (double)GetValue(PanelStartAngleOffsetProperty); }set { SetValue(PanelStartAngleOffsetProperty, value); }}public static readonly DependencyProperty PanelStartAngleOffsetProperty =DependencyProperty.Register("PanelStartAngleOffset", typeof(double), typeof(DrawingControl), new PropertyMetadata(0d));public string PanelMultipleDescription{get { return (string)GetValue(PanelMultipleDescriptionProperty); }set { SetValue(PanelMultipleDescriptionProperty, value); }}public static readonly DependencyProperty PanelMultipleDescriptionProperty =DependencyProperty.Register("PanelMultipleDescription", typeof(string), typeof(DrawingControl), new PropertyMetadata(default));public double PanelMultipleSpace{get { return (double)GetValue(PanelMultipleSpaceProperty); }set { SetValue(PanelMultipleSpaceProperty, value); }}public static readonly DependencyProperty PanelMultipleSpaceProperty =DependencyProperty.Register("PanelMultipleSpace", typeof(double), typeof(DrawingControl), new PropertyMetadata(0d));public Thickness InnerMargin{get { return (Thickness)GetValue(InnerMarginProperty); }set { SetValue(InnerMarginProperty, value); }}public static readonly DependencyProperty InnerMarginProperty =DependencyProperty.Register("InnerMargin", typeof(Thickness), typeof(DrawingControl), new PropertyMetadata(new Thickness(50d)));public Brush InnerBackground{get { return (Brush)GetValue(InnerBackgroundProperty); }set { SetValue(InnerBackgroundProperty, value); }}public static readonly DependencyProperty InnerBackgroundProperty =DependencyProperty.Register("InnerBackground", typeof(Brush), typeof(DrawingControl), new PropertyMetadata(Brushes.Transparent));public CornerRadius InnerCornerRadius{get { return (CornerRadius)GetValue(InnerCornerRadiusProperty); }set { SetValue(InnerCornerRadiusProperty, value); }}public static readonly DependencyProperty InnerCornerRadiusProperty =DependencyProperty.Register("InnerCornerRadius", typeof(CornerRadius), typeof(DrawingControl), new PropertyMetadata(default));public Thickness InnerBorderThickness{get { return (Thickness)GetValue(InnerBorderThicknessProperty); }set { SetValue(InnerBorderThicknessProperty, value); }}public static readonly DependencyProperty InnerBorderThicknessProperty =DependencyProperty.Register("InnerBorderThickness", typeof(Thickness), typeof(DrawingControl), new PropertyMetadata(new Thickness(1d)));public Brush InnerBorderBrush{get { return (Brush)GetValue(InnerBorderBrushProperty); }set { SetValue(InnerBorderBrushProperty, value); }}public static readonly DependencyProperty InnerBorderBrushProperty =DependencyProperty.Register("InnerBorderBrush", typeof(Brush), typeof(DrawingControl), new PropertyMetadata(Brushes.Gray));public double Scale{get { return (double)GetValue(ScaleProperty); }set { SetValue(ScaleProperty, value); }}public static readonly DependencyProperty ScaleProperty =DependencyProperty.Register("Scale", typeof(double), typeof(DrawingControl), new PropertyMetadata(0.4d, OnScalePropertyChangedCallBack));public object Content{get { return (object)GetValue(ContentProperty); }set { SetValue(ContentProperty, value); }}public static readonly DependencyProperty ContentProperty =DependencyProperty.Register("Content", typeof(object), typeof(DrawingControl), new PropertyMetadata(default));public DataTemplate ContentTemplate{get { return (DataTemplate)GetValue(ContentTemplateProperty); }set { SetValue(ContentTemplateProperty, value); }}public static readonly DependencyProperty ContentTemplateProperty =DependencyProperty.Register("ContentTemplate", typeof(DataTemplate), typeof(DrawingControl), new PropertyMetadata(default));public DataTemplateSelector ContentTemplateSelector{get { return (DataTemplateSelector)GetValue(ContentTemplateSelectorProperty); }set { SetValue(ContentTemplateSelectorProperty, value); }}public static readonly DependencyProperty ContentTemplateSelectorProperty =DependencyProperty.Register("ContentTemplateSelector", typeof(DataTemplateSelector), typeof(DrawingControl), new PropertyMetadata(default));public string ContentStringFormat{get { return (string)GetValue(ContentStringFormatProperty); }set { SetValue(ContentStringFormatProperty, value); }}public static readonly DependencyProperty ContentStringFormatProperty =DependencyProperty.Register("ContentStringFormat", typeof(string), typeof(DrawingControl), new PropertyMetadata(default));public string ContentSource{get { return (string)GetValue(ContentSourceProperty); }set { SetValue(ContentSourceProperty, value); }}public static readonly DependencyProperty ContentSourceProperty =DependencyProperty.Register("ContentSource", typeof(string), typeof(DrawingControl), new PropertyMetadata("Content"));private static void OnScalePropertyChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e){if (!(d is DrawingControl drawing))return;//drawing.InnerMargin = new Thickness(vMin * drawing.Scale);if (drawing._Border != null){var vMin = Math.Min(drawing.RenderSize.Width, drawing.RenderSize.Height);drawing._Border.Width = vMin * drawing.Scale;drawing._Border.Height = vMin * drawing.Scale;}}}
}
二、创建 DrawingPanel.cs 继承 Panel代码如下。
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using WPFDevelopers.Assists;
using WPFDevelopers.Utilities;namespace WPFDevelopers.Controls
{public enum DrawingMode{Left,Right,Top,Bottom,}public class DrawingPanel : Panel{public static readonly DependencyProperty BorderBrushProperty =DependencyProperty.Register("BorderBrush", typeof(Brush), typeof(DrawingPanel), new PropertyMetadata(default, OnRenderPropertyChangedCallBack));public static readonly DependencyProperty BorderThicknessProperty =DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(DrawingPanel), new PropertyMetadata(new Thickness(), OnRenderPropertyChangedCallBack));public static readonly DependencyProperty CornerRadiusProperty =DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(DrawingPanel), new PropertyMetadata(new CornerRadius(), OnRenderPropertyChangedCallBack));public static readonly DependencyProperty OffsetProperty =DependencyProperty.Register("Offset", typeof(double), typeof(DrawingPanel), new PropertyMetadata(0d, OnRenderPropertyChangedCallBack));public static readonly DependencyProperty ModeProperty =DependencyProperty.Register("Mode", typeof(DrawingMode), typeof(DrawingPanel), new PropertyMetadata(default(DrawingMode), OnRenderPropertyChangedCallBack));public static readonly DependencyProperty StartOffsetAngleProperty =DependencyProperty.Register("StartOffsetAngle", typeof(double), typeof(DrawingPanel), new PropertyMetadata(0d, OnRenderPropertyChangedCallBack));public Brush BorderBrush{get { return (Brush)GetValue(BorderBrushProperty); }set { SetValue(BorderBrushProperty, value); }}public Thickness BorderThickness{get { return (Thickness)GetValue(BorderThicknessProperty); }set { SetValue(BorderThicknessProperty, value); }}public CornerRadius CornerRadius{get { return (CornerRadius)GetValue(CornerRadiusProperty); }set { SetValue(CornerRadiusProperty, value); }}public double Offset{get { return (double)GetValue(OffsetProperty); }set { SetValue(OffsetProperty, value); }}public DrawingMode Mode{get { return (DrawingMode)GetValue(ModeProperty); }set { SetValue(ModeProperty, value); }}public double StartOffsetAngle{get { return (double)GetValue(StartOffsetAngleProperty); }set { SetValue(StartOffsetAngleProperty, value); }}public string MultipleArrayDescription{get { return (string)GetValue(MultipleArrayDescriptionProperty); }set { SetValue(MultipleArrayDescriptionProperty, value); }}public static readonly DependencyProperty MultipleArrayDescriptionProperty =DependencyProperty.Register("MultipleArrayDescription", typeof(string), typeof(DrawingPanel), new PropertyMetadata(default, OnRenderPropertyChangedCallBack));public double LayerSpace{get { return (double)GetValue(LayerSpaceProperty); }set { SetValue(LayerSpaceProperty, value); }}public static readonly DependencyProperty LayerSpaceProperty =DependencyProperty.Register("LayerSpace", typeof(double), typeof(DrawingPanel), new PropertyMetadata(5d, OnRenderPropertyChangedCallBack));private List<int> _MultipleArray = default;private static void OnRenderPropertyChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e){if (!(d is DrawingPanel drawing))return;drawing.InvalidateVisual();}protected override Size MeasureOverride(Size availableSize){double width = 0;double height = 0;foreach (var child in InternalChildren){if (!(child is UIElement uiElement))continue;uiElement.Measure(availableSize);width = Math.Max(width, uiElement.DesiredSize.Width);height = Math.Max(height, uiElement.DesiredSize.Height);uiElement.RenderSize = new Size(width, height);}if (double.IsPositiveInfinity(availableSize.Width))availableSize.Width = width * 4 + Offset * 2;if (double.IsPositiveInfinity(availableSize.Height))availableSize.Height = height * 4 + Offset * 2;return availableSize;}protected override Size ArrangeOverride(Size finalSize){if (double.IsPositiveInfinity(finalSize.Width)|| double.IsPositiveInfinity(finalSize.Height)|| double.IsNaN(finalSize.Width)|| double.IsNaN(finalSize.Height)|| double.IsNegativeInfinity(finalSize.Width)|| double.IsNegativeInfinity(finalSize.Height))return finalSize;double realValue = Math.Min(finalSize.Width, finalSize.Height);Size desiredSzie = new Size(realValue, realValue);MultipleArrangeOverride();if (IsMuliple())ArrangeOverrideMultiple(realValue);elseArrangeOverrideSingle(realValue);return desiredSzie;}protected override void OnRender(DrawingContext dc){OnRenderBackground(dc);}private bool OnRenderBackground(DrawingContext dc){Thickness border = BorderThickness;Brush borderBrush = BorderBrush;Brush backGround = Background;CornerRadius cornerRadius = CornerRadius;double outerCornerRadius = cornerRadius.TopLeft; // Already validated that all corners have the same radiusbool roundedCorners = !DoubleUtil.IsZero(outerCornerRadius);if (!border.IsZero() && borderBrush != null){Pen pen = new Pen();pen.Brush = borderBrush;pen.Thickness = border.Left;if (borderBrush.IsFrozen)pen.Freeze();double halfThickness;if (border.IsUniform()){halfThickness = pen.Thickness * 0.5;Rect rect = new Rect(new Point(halfThickness, halfThickness), new Point(RenderSize.Width - halfThickness, RenderSize.Height - halfThickness));if (roundedCorners){dc.DrawRoundedRectangle(backGround,pen,rect,outerCornerRadius,outerCornerRadius);}else{dc.DrawRectangle(backGround,pen,rect);}}else{if (DoubleUtil.GreaterThan(border.Left, 0)){halfThickness = pen.Thickness * 0.5;dc.DrawLine(pen,new Point(halfThickness, 0),new Point(halfThickness, RenderSize.Height));}if (DoubleUtil.GreaterThan(border.Right, 0)){halfThickness = pen.Thickness * 0.5;dc.DrawLine(pen,new Point(RenderSize.Width - halfThickness, 0),new Point(RenderSize.Width - halfThickness, RenderSize.Height));}if (DoubleUtil.GreaterThan(border.Top, 0)){halfThickness = pen.Thickness * 0.5;dc.DrawLine(pen,new Point(0, halfThickness),new Point(RenderSize.Width, halfThickness));}if (DoubleUtil.GreaterThan(border.Bottom, 0)){halfThickness = pen.Thickness * 0.5;dc.DrawLine(pen,new Point(0, RenderSize.Height - halfThickness),new Point(RenderSize.Width, RenderSize.Height - halfThickness));}}}else{Rect rect = new Rect(new Point(0, 0), new Point(RenderSize.Width, RenderSize.Height));if (roundedCorners){dc.DrawRoundedRectangle(backGround,null,rect,outerCornerRadius,outerCornerRadius);}else{dc.DrawRectangle(backGround,null,rect);}}return true;}private bool MultipleArrangeOverride(){_MultipleArray?.Clear();_MultipleArray = default;if (string.IsNullOrWhiteSpace(MultipleArrayDescription))return true;_MultipleArray = new List<int>();var vArray = MultipleArrayDescription.Split(',');foreach (var item in vArray){if (string.IsNullOrWhiteSpace(item))continue;if (!int.TryParse(item, out var vResult))continue;if (vResult <= 0)continue;//var v = _MultipleArray.Where(ix => ix == vResult).ToList();//if (v.Count == 0)//_MultipleArray.Add(vResult);_MultipleArray.Add(vResult);}int nCount = 0;foreach (var item in _MultipleArray)nCount += item;if (nCount < InternalChildren.Count)_MultipleArray.Add(InternalChildren.Count - nCount);return true;}private bool ArrangeOverrideSingle(double realValue){var vInternalChildren = InternalChildren;double angle = 360d / vInternalChildren.Count;switch (Mode){case DrawingMode.Left:ArrangeOverride_Left(vInternalChildren, realValue, angle);break;case DrawingMode.Right:ArrangeOverride_Right(vInternalChildren, realValue, angle);break;case DrawingMode.Top:ArrangeOverride_Top(vInternalChildren, realValue, angle);break;case DrawingMode.Bottom:ArrangeOverride_Bottom(vInternalChildren, realValue, angle);break;default:ArrangeOverride_Left(vInternalChildren, realValue, angle);break;}return true;}private bool ArrangeOverride_Left(UIElementCollection internalChildren, double realValue, double angle){if (internalChildren == null || internalChildren.Count <= 0)return false;if (realValue <= 0 || angle <= 0)return false;int index = 0;foreach (var child in internalChildren){index++;if (!(child is UIElement uiElement))continue;if (uiElement.DesiredSize.IsEmpty)continue;if (DoubleUtil.IsZero(uiElement.DesiredSize.Width) || DoubleUtil.IsZero(uiElement.DesiredSize.Height))continue;Point size = new Point(Offset, (realValue - uiElement.DesiredSize.Height) / 2d);uiElement.Arrange(new Rect(size, uiElement.DesiredSize));var vRotateTransform = new RotateTransform(){Angle = angle * (index - 1) + StartOffsetAngle,};var vRealValue = realValue - 2 * Offset;if (vRealValue <= 0)return false;var vRet = vRealValue / 2 / uiElement.DesiredSize.Width;uiElement.RenderTransformOrigin = new Point(vRet, 0.5);uiElement.RenderTransform = vRotateTransform;}return true;}private bool ArrangeOverride_Right(UIElementCollection internalChildren, double realValue, double angle){if (internalChildren == null || internalChildren.Count <= 0)return false;if (realValue <= 0 || angle <= 0)return false;int index = 0;foreach (var child in internalChildren){index++;if (!(child is UIElement uiElement))continue;if (uiElement.DesiredSize.IsEmpty)continue;if (DoubleUtil.IsZero(uiElement.DesiredSize.Width) || DoubleUtil.IsZero(uiElement.DesiredSize.Height))continue;Point size = new Point(realValue - Offset - uiElement.DesiredSize.Width, (realValue - uiElement.DesiredSize.Height) / 2d);uiElement.Arrange(new Rect(size, uiElement.DesiredSize));var vRotateTransform = new RotateTransform(){Angle = angle * (index - 1) + StartOffsetAngle,};var vRealValue = realValue - 2 * Offset;if (vRealValue <= 0)return false;var vRet = vRealValue / 2 / uiElement.DesiredSize.Width - 1;uiElement.RenderTransformOrigin = new Point(-vRet, 0.5);uiElement.RenderTransform = vRotateTransform;}return true;}private bool ArrangeOverride_Top(UIElementCollection internalChildren, double realValue, double angle){if (internalChildren == null || internalChildren.Count <= 0)return false;if (realValue <= 0 || angle <= 0)return false;int index = 0;foreach (var child in internalChildren){index++;if (!(child is UIElement uiElement))continue;if (uiElement.DesiredSize.IsEmpty)continue;if (DoubleUtil.IsZero(uiElement.DesiredSize.Width) || DoubleUtil.IsZero(uiElement.DesiredSize.Height))continue;Point size = new Point((realValue - uiElement.DesiredSize.Width) / 2d, Offset);uiElement.Arrange(new Rect(size, uiElement.DesiredSize));var vRotateTransform = new RotateTransform(){Angle = angle * (index - 1) + StartOffsetAngle,};var vRealValue = realValue - 2 * Offset;if (vRealValue <= 0)return false;var vRet = vRealValue / 2 / uiElement.DesiredSize.Height;uiElement.RenderTransformOrigin = new Point(0.5, vRet);uiElement.RenderTransform = vRotateTransform;}return true;}private bool ArrangeOverride_Bottom(UIElementCollection internalChildren, double realValue, double angle){if (internalChildren == null || internalChildren.Count <= 0)return false;if (realValue <= 0 || angle <= 0)return false;int index = 0;foreach (var child in internalChildren){index++;if (!(child is UIElement uiElement))continue;if (uiElement.DesiredSize.IsEmpty)continue;if (DoubleUtil.IsZero(uiElement.DesiredSize.Width) || DoubleUtil.IsZero(uiElement.DesiredSize.Height))continue;Point size = new Point((realValue - uiElement.DesiredSize.Width) / 2d, realValue - Offset - uiElement.DesiredSize.Height);uiElement.Arrange(new Rect(size, uiElement.DesiredSize));var vRotateTransform = new RotateTransform(){Angle = angle * (index - 1) + StartOffsetAngle,};var vRealValue = realValue - 2 * Offset;if (vRealValue <= 0)return false;var vRet = vRealValue / 2 / uiElement.DesiredSize.Height - 1;uiElement.RenderTransformOrigin = new Point(0.5, -vRet);uiElement.RenderTransform = vRotateTransform;}return true;}private bool IsMuliple(){if (_MultipleArray?.Count > 0){int nCount = 0;foreach (var item in _MultipleArray)nCount += item;if (nCount > InternalChildren.Count)return false;return true;}return false;}private bool ArrangeOverrideMultiple(double realValue){double offset = Offset;var vInternalChildren = InternalChildren;int nStartIndex = 0;double lastMaxWidth = 0;double lastMaxHeight = 0;int nLoopIndex = 0;foreach (var item in _MultipleArray){double angle = 360d / item;int nIndex = 0;double maxWidth = 0;double maxHeight = 0;for (int i = nStartIndex; i < nStartIndex + item; ++i){var child = vInternalChildren[i];Size vSize = Size.Empty;switch (Mode){case DrawingMode.Left:{var vOffset = offset + lastMaxWidth + LayerSpace * nLoopIndex;ArrangeOverride_Left(child, nIndex, vOffset, realValue, angle, out vSize);}break;case DrawingMode.Right:{var vOffset = offset + lastMaxWidth + LayerSpace * nLoopIndex;ArrangeOverride_Right(child, nIndex, vOffset, realValue, angle, out vSize);}break;case DrawingMode.Top:{var vOffset = offset + lastMaxHeight + LayerSpace * nLoopIndex;ArrangeOverride_Top(child, nIndex, vOffset, realValue, angle, out vSize);}break;case DrawingMode.Bottom:{var vOffset = offset + lastMaxHeight + LayerSpace * nLoopIndex;ArrangeOverride_Bottom(child, nIndex, vOffset, realValue, angle, out vSize);}break;default:{var vOffset = offset + lastMaxWidth + LayerSpace * nLoopIndex;ArrangeOverride_Left(child, nIndex, vOffset, realValue, angle, out vSize);}break;}maxWidth = Math.Max(maxWidth, vSize.Width);maxHeight = Math.Max(maxHeight, vSize.Height);nIndex++;}lastMaxWidth += maxWidth;lastMaxHeight += maxHeight;nStartIndex += item;nLoopIndex++;}return true;}private bool ArrangeOverride_Left(UIElement uiElement, int index, double offset, double realValue, double angle, out Size desiredSize){desiredSize = Size.Empty;if (realValue <= 0 || angle <= 0)return false;if (uiElement.DesiredSize.IsEmpty)return false;if (DoubleUtil.IsZero(uiElement.DesiredSize.Width) || DoubleUtil.IsZero(uiElement.DesiredSize.Height))return false;Point size = new Point(offset, (realValue - uiElement.DesiredSize.Height) / 2d);uiElement.Arrange(new Rect(size, uiElement.DesiredSize));desiredSize = uiElement.DesiredSize;var vRotateTransform = new RotateTransform(){Angle = angle * index + StartOffsetAngle,};var vRealValue = realValue - 2 * offset;if (vRealValue <= 0)return false;var vRet = vRealValue / 2 / uiElement.DesiredSize.Width;uiElement.RenderTransformOrigin = new Point(vRet, 0.5);uiElement.RenderTransform = vRotateTransform;return true;}private bool ArrangeOverride_Right(UIElement uiElement, int index, double offset, double realValue, double angle, out Size desiredSize){desiredSize = Size.Empty;if (realValue <= 0 || angle <= 0)return false;if (uiElement.DesiredSize.IsEmpty)return false;if (DoubleUtil.IsZero(uiElement.DesiredSize.Width) || DoubleUtil.IsZero(uiElement.DesiredSize.Height))return false;Point size = new Point(realValue - offset - uiElement.DesiredSize.Width, (realValue - uiElement.DesiredSize.Height) / 2d);uiElement.Arrange(new Rect(size, uiElement.DesiredSize));desiredSize = uiElement.DesiredSize;var vRotateTransform = new RotateTransform(){Angle = angle * index + StartOffsetAngle,};var vRealValue = realValue - 2 * offset;if (vRealValue <= 0)return false;var vRet = vRealValue / 2 / uiElement.DesiredSize.Width - 1;uiElement.RenderTransformOrigin = new Point(-vRet, 0.5);uiElement.RenderTransform = vRotateTransform;return true;}private bool ArrangeOverride_Top(UIElement uiElement, int index, double offset, double realValue, double angle, out Size desiredSize){desiredSize = Size.Empty;if (realValue <= 0 || angle <= 0)return false;if (uiElement.DesiredSize.IsEmpty)return false;if (DoubleUtil.IsZero(uiElement.DesiredSize.Width) || DoubleUtil.IsZero(uiElement.DesiredSize.Height))return false;Point size = new Point((realValue - uiElement.DesiredSize.Width) / 2d, offset);uiElement.Arrange(new Rect(size, uiElement.DesiredSize));desiredSize = uiElement.DesiredSize;var vRotateTransform = new RotateTransform(){Angle = angle * index + StartOffsetAngle,};var vRealValue = realValue - 2 * offset;if (vRealValue <= 0)return false;var vRet = vRealValue / 2 / uiElement.DesiredSize.Height;uiElement.RenderTransformOrigin = new Point(0.5, vRet);uiElement.RenderTransform = vRotateTransform;return true;}private bool ArrangeOverride_Bottom(UIElement uiElement, int index, double offset, double realValue, double angle, out Size desiredSize){desiredSize = Size.Empty;if (realValue <= 0 || angle <= 0)return false;if (uiElement.DesiredSize.IsEmpty)return false;if (DoubleUtil.IsZero(uiElement.DesiredSize.Width) || DoubleUtil.IsZero(uiElement.DesiredSize.Height))return false;Point size = new Point((realValue - uiElement.DesiredSize.Width) / 2d, realValue - offset - uiElement.DesiredSize.Height);uiElement.Arrange(new Rect(size, uiElement.DesiredSize));desiredSize = uiElement.DesiredSize;var vRotateTransform = new RotateTransform(){Angle = angle * index + StartOffsetAngle,};var vRealValue = realValue - 2 * offset;if (vRealValue <= 0)return false;var vRet = vRealValue / 2 / uiElement.DesiredSize.Height - 1;uiElement.RenderTransformOrigin = new Point(0.5, -vRet);uiElement.RenderTransform = vRotateTransform;return true;}}
}
三、Drawing.xaml代码如下
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:controls="clr-namespace:WPFDevelopers.Controls"><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Basic/ControlBasic.xaml"/></ResourceDictionary.MergedDictionaries><Style x:Key="DrawingControlItem"TargetType="{x:Type ListBoxItem}"BasedOn="{StaticResource ControlBasicStyle}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="ListBoxItem"><Border SnapsToDevicePixels="True"><ContentPresenter /></Border><ControlTemplate.Triggers><Trigger Property="IsSelected"Value="true"><Setter Property="Background"Value="{x:Null}" /></Trigger><Trigger Property="IsEnabled"Value="false"><Setter Property="Foreground"Value="{x:Null}" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style><Style TargetType="controls:DrawingControl" BasedOn="{StaticResource ControlBasicStyle}"><Setter Property="Background" Value="Transparent"/><Setter Property="BorderBrush" Value="{x:Null}"/><Setter Property="BorderThickness" Value="0"/><Setter Property="Foreground" Value="{StaticResource PrimaryTextSolidColorBrush}"/><Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/><Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/><Setter Property="ScrollViewer.CanContentScroll" Value="true"/><Setter Property="ScrollViewer.PanningMode" Value="Both"/><Setter Property="Stylus.IsFlicksEnabled" Value="False"/><Setter Property="VerticalContentAlignment" Value="Center"/><Setter Property="Padding" Value="0"/><Setter Property="ItemContainerStyle" Value="{StaticResource DrawingControlItem}"/><Setter Property="Margin" Value="0"/><Setter Property="ItemsPanel"><Setter.Value><ItemsPanelTemplate><controls:DrawingPanel x:Name="PART_DrawingPanel" Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:DrawingControl}, Path=PanelBackground, Mode=TwoWay}" CornerRadius="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:DrawingControl}, Path=PanelCornerRadius, Mode=TwoWay}" BorderThickness="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:DrawingControl}, Path=PanelBorderThinckness, Mode=TwoWay}"BorderBrush="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:DrawingControl}, Path=PanelBorderBrush, Mode=TwoWay}"Offset="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:DrawingControl}, Path=ItemOffset, Mode=TwoWay}"Mode="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:DrawingControl}, Path=PanelDrawingMode, Mode=TwoWay}"StartOffsetAngle="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:DrawingControl}, Path=PanelStartAngleOffset, Mode=TwoWay}"MultipleArrayDescription="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:DrawingControl}, Path=PanelMultipleDescription, Mode=TwoWay}"LayerSpace="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:DrawingControl}, Path=PanelMultipleSpace, Mode=TwoWay}"/></ItemsPanelTemplate></Setter.Value></Setter><!--<Setter Property="ItemContainerStyle" Value="{StaticResource DrawingElementStyle}"/>--><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type controls:DrawingControl}"><Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="0" SnapsToDevicePixels="true"><Grid><ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}"><ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/></ScrollViewer><Border x:Name="PART_InnerBorder"VerticalAlignment="Center"HorizontalAlignment="Center"Background="{TemplateBinding InnerBackground}" BorderBrush="{TemplateBinding InnerBorderBrush}"BorderThickness="{TemplateBinding InnerBorderThickness}"CornerRadius="{TemplateBinding InnerCornerRadius}" Padding="3" ><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/></Border></Grid></Border><ControlTemplate.Triggers><Trigger Property="IsEnabled" Value="false"><Setter Property="Opacity" Value="0.4"/></Trigger><MultiTrigger><MultiTrigger.Conditions><Condition Property="IsGrouping" Value="true"/></MultiTrigger.Conditions><Setter Property="ScrollViewer.CanContentScroll" Value="false"/></MultiTrigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style></ResourceDictionary>
四、DrawingExample.xaml代码如下
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.DrawingExample"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"xmlns:wpfdev="https://github.com/yanjinhuagood/WPFDevelopers" xmlns:vm="clr-namespace:WPFDevelopers.Samples.ViewModels"mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"><UserControl.DataContext><vm:DrawingExampleVM/></UserControl.DataContext><UniformGrid Columns="3" Rows="2"><wpfdev:DrawingControl InnerBackground="{StaticResource SuccessSolidColorBrush}"Content="反应盘"><ListBoxItem Content="盘1"/><ListBoxItem Content="盘2"/><ListBoxItem Content="盘3"/><ListBoxItem Content="盘4"/><ListBoxItem Content="盘5"/></wpfdev:DrawingControl><wpfdev:DrawingControl ItemsSource="{Binding Drawings}"Content="试剂仓"PanelBorderThinckness="0" PanelBackground="#FFF2F2F2" InnerBorderThickness="1" InnerBorderBrush="{StaticResource DangerSolidColorBrush}"InnerBackground="White" PanelDrawingMode="Top"><wpfdev:DrawingControl.ItemTemplate><DataTemplate><!--<Border CornerRadius="5"Width="28" Height="45" BorderThickness="1" BorderBrush="Green"Background="Red"><TextBlock Text="{Binding Number}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Normal" Foreground="White"/></Border>--><Button Style="{StaticResource DefaultButton}"Content="{Binding Number}"/></DataTemplate></wpfdev:DrawingControl.ItemTemplate></wpfdev:DrawingControl><wpfdev:DrawingControl ItemsSource="{Binding Drawings}"Content="试剂仓"PanelBorderThinckness="0" PanelBackground="#FFF2F2F2" InnerBorderThickness="1" InnerBackground="{StaticResource WarningSolidColorBrush}" PanelDrawingMode="Right"PanelMultipleSpace="10"PanelMultipleDescription="5"><wpfdev:DrawingControl.ItemTemplate><DataTemplate><!--<Border CornerRadius="30" Width="30" Height="30" BorderThickness="1" BorderBrush="Green" Background="Red"><TextBlock Text="{Binding Number}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Normal" Foreground="White"/></Border>--><CheckBox Content="{Binding Number}"/></DataTemplate></wpfdev:DrawingControl.ItemTemplate></wpfdev:DrawingControl><wpfdev:DrawingControl ItemsSource="{Binding Drawings}"Content="试剂仓"PanelBorderThinckness="0" PanelBackground="#FFF2F2F2" InnerBorderThickness="1" InnerBackground="White" PanelDrawingMode="Bottom"PanelMultipleSpace="2"PanelMultipleDescription="2,3"><wpfdev:DrawingControl.ItemTemplate><DataTemplate><!--<Border CornerRadius="5" Width="28" Height="45" BorderThickness="1" BorderBrush="Green" Background="Red"><TextBlock Text="{Binding Number}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Normal" Foreground="White"/></Border>--><RadioButton Content="{Binding Number}"/></DataTemplate></wpfdev:DrawingControl.ItemTemplate></wpfdev:DrawingControl><wpfdev:DrawingControl ItemsSource="{Binding Drawings}"Content="试剂仓"PanelBorderThinckness="0" PanelBackground="#FFF2F2F2" InnerBorderThickness="1" InnerBackground="White" PanelDrawingMode="Left"PanelMultipleSpace="0"PanelMultipleDescription="3,3"><wpfdev:DrawingControl.ItemTemplate><DataTemplate><!--<Border CornerRadius="5" Width="28" Height="45" BorderThickness="1" BorderBrush="Green" Background="Red"><TextBlock Text="{Binding Number}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Normal" Foreground="White"/></Border>--><Button Style="{StaticResource PrimaryButton}" Content="{Binding Number}"/></DataTemplate></wpfdev:DrawingControl.ItemTemplate></wpfdev:DrawingControl></UniformGrid>
</UserControl>
02
—
效果预览
鸣谢素材提供者 - 吴锋
源码地址如下
github:https://github.com/WPFDevelopersOrg
gitee:https://gitee.com/WPFDevelopersOrg
WPF开发者QQ群: 340500857
Github:https://github.com/WPFDevelopersOrg
出处:https://www.cnblogs.com/yanjinhua
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
转载请著名作者 出处 https://github.com/WPFDevelopersOrg
扫一扫关注我们,
更多知识早知道!
点击阅读原文可跳转至源代码