WaterfallPanel.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. using System.Linq;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. using HandyControl.Data;
  5. using HandyControl.Expression.Drawing;
  6. using HandyControl.Tools;
  7. namespace HandyControl.Controls;
  8. public class WaterfallPanel : Panel
  9. {
  10. public static readonly DependencyProperty GroupsProperty = DependencyProperty.Register(
  11. nameof(Groups), typeof(int), typeof(WaterfallPanel), new FrameworkPropertyMetadata(
  12. ValueBoxes.Int2Box, FrameworkPropertyMetadataOptions.AffectsMeasure), IsGroupsValid);
  13. public int Groups
  14. {
  15. get => (int) GetValue(GroupsProperty);
  16. set => SetValue(GroupsProperty, value);
  17. }
  18. private static bool IsGroupsValid(object value) => (int) value >= 1;
  19. public static readonly DependencyProperty AutoGroupProperty = DependencyProperty.Register(
  20. nameof(AutoGroup), typeof(bool), typeof(WaterfallPanel), new FrameworkPropertyMetadata(
  21. ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsMeasure));
  22. public bool AutoGroup
  23. {
  24. get => (bool) GetValue(AutoGroupProperty);
  25. set => SetValue(AutoGroupProperty, ValueBoxes.BooleanBox(value));
  26. }
  27. public static readonly DependencyProperty DesiredLengthProperty = DependencyProperty.Register(
  28. nameof(DesiredLength), typeof(double), typeof(WaterfallPanel), new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
  29. FrameworkPropertyMetadataOptions.AffectsMeasure), ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
  30. public double DesiredLength
  31. {
  32. get => (double) GetValue(DesiredLengthProperty);
  33. set => SetValue(DesiredLengthProperty, value);
  34. }
  35. public static readonly DependencyProperty OrientationProperty =
  36. StackPanel.OrientationProperty.AddOwner(typeof(WaterfallPanel),
  37. new FrameworkPropertyMetadata(Orientation.Horizontal,
  38. FrameworkPropertyMetadataOptions.AffectsMeasure));
  39. public Orientation Orientation
  40. {
  41. get => (Orientation) GetValue(OrientationProperty);
  42. set => SetValue(OrientationProperty, value);
  43. }
  44. private int CaculateGroupCount(Orientation orientation, PanelUvSize size)
  45. {
  46. if (!AutoGroup)
  47. {
  48. return Groups;
  49. }
  50. var itemLength = DesiredLength;
  51. if (MathHelper.IsVerySmall(itemLength))
  52. {
  53. return Groups;
  54. }
  55. return (int) (size.U / itemLength);
  56. }
  57. protected override Size ArrangeOverride(Size finalSize)
  58. {
  59. var orientation = Orientation;
  60. var uvConstraint = new PanelUvSize(orientation, finalSize);
  61. var groups = CaculateGroupCount(orientation, uvConstraint);
  62. if (groups < 1)
  63. {
  64. return finalSize;
  65. }
  66. var vArr = new double[groups].ToList();
  67. var itemU = uvConstraint.U / groups;
  68. var children = InternalChildren;
  69. for (int i = 0, count = children.Count; i < count; i++)
  70. {
  71. var child = children[i];
  72. if (child == null)
  73. {
  74. continue;
  75. }
  76. var minIndex = vArr.IndexOf(vArr.Min());
  77. var minV = vArr[minIndex];
  78. var childUvSize = new PanelUvSize(orientation, child.DesiredSize);
  79. var childSize = new PanelUvSize(orientation, itemU, childUvSize.V);
  80. var childRectSize = new PanelUvSize(orientation, minIndex * itemU, minV);
  81. child.Arrange(new Rect(new Point(childRectSize.U, childRectSize.V), childSize.ScreenSize));
  82. vArr[minIndex] = minV + childUvSize.V;
  83. }
  84. return finalSize;
  85. }
  86. protected override Size MeasureOverride(Size constraint)
  87. {
  88. var orientation = Orientation;
  89. var uvConstraint = new PanelUvSize(orientation, constraint);
  90. var groups = CaculateGroupCount(orientation, uvConstraint);
  91. if (groups < 1)
  92. {
  93. return constraint;
  94. }
  95. var vArr = new double[groups].ToList();
  96. var itemU = uvConstraint.U / groups;
  97. if (double.IsNaN(itemU) || double.IsInfinity(itemU))
  98. {
  99. return constraint;
  100. }
  101. var children = InternalChildren;
  102. for (int i = 0, count = children.Count; i < count; i++)
  103. {
  104. var child = children[i];
  105. if (child == null)
  106. {
  107. continue;
  108. }
  109. child.Measure(constraint);
  110. var sz = new PanelUvSize(orientation, child.DesiredSize);
  111. var minIndex = vArr.IndexOf(vArr.Min());
  112. var minV = vArr[minIndex];
  113. vArr[minIndex] = minV + sz.V;
  114. }
  115. uvConstraint = new PanelUvSize(orientation, new Size(uvConstraint.ScreenSize.Width, vArr.Max()));
  116. return uvConstraint.ScreenSize;
  117. }
  118. }