CirclePanel.cs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. using System;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. using System.Windows.Media;
  5. using HandyControl.Data;
  6. namespace HandyControl.Controls;
  7. public class CirclePanel : Panel
  8. {
  9. public static readonly DependencyProperty DiameterProperty = DependencyProperty.Register(
  10. nameof(Diameter), typeof(double), typeof(CirclePanel), new FrameworkPropertyMetadata(170.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
  11. public double Diameter
  12. {
  13. get => (double) GetValue(DiameterProperty);
  14. set => SetValue(DiameterProperty, value);
  15. }
  16. public static readonly DependencyProperty KeepVerticalProperty = DependencyProperty.Register(
  17. nameof(KeepVertical), typeof(bool), typeof(CirclePanel), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsMeasure));
  18. public bool KeepVertical
  19. {
  20. get => (bool) GetValue(KeepVerticalProperty);
  21. set => SetValue(KeepVerticalProperty, ValueBoxes.BooleanBox(value));
  22. }
  23. public static readonly DependencyProperty OffsetAngleProperty = DependencyProperty.Register(
  24. nameof(OffsetAngle), typeof(double), typeof(CirclePanel), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsMeasure));
  25. public double OffsetAngle
  26. {
  27. get => (double) GetValue(OffsetAngleProperty);
  28. set => SetValue(OffsetAngleProperty, value);
  29. }
  30. protected override Size MeasureOverride(Size availableSize)
  31. {
  32. var diameter = Diameter;
  33. if (Children.Count == 0) return new Size(diameter, diameter);
  34. var newSize = new Size(diameter, diameter);
  35. foreach (UIElement element in Children)
  36. {
  37. element.Measure(newSize);
  38. }
  39. return newSize;
  40. }
  41. protected override Size ArrangeOverride(Size finalSize)
  42. {
  43. var keepVertical = KeepVertical;
  44. var offsetAngle = OffsetAngle;
  45. var i = 0;
  46. var perDeg = 360.0 / Children.Count;
  47. var radius = Diameter / 2;
  48. foreach (UIElement element in Children)
  49. {
  50. var centerX = element.DesiredSize.Width / 2.0;
  51. var centerY = element.DesiredSize.Height / 2.0;
  52. var angle = perDeg * i++ + offsetAngle;
  53. var transform = new RotateTransform
  54. {
  55. CenterX = centerX,
  56. CenterY = centerY,
  57. Angle = keepVertical ? 0 : angle
  58. };
  59. element.RenderTransform = transform;
  60. var r = Math.PI * angle / 180.0;
  61. var x = radius * Math.Cos(r);
  62. var y = radius * Math.Sin(r);
  63. var rectX = x + finalSize.Width / 2 - centerX;
  64. var rectY = y + finalSize.Height / 2 - centerY;
  65. element.Arrange(new Rect(rectX, rectY, element.DesiredSize.Width, element.DesiredSize.Height));
  66. }
  67. return finalSize;
  68. }
  69. }