You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
7.3 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows.Controls;
  7. using System.Windows;
  8. using System.Xml.Linq;
  9. using System.Drawing;
  10. using System.Reflection;
  11. namespace BPA.UIControl
  12. {
  13. /// <summary>
  14. /// Panel 帮助类
  15. /// </summary>
  16. public class PanelHelper
  17. {
  18. /// <summary>
  19. /// 间距
  20. /// </summary>
  21. public static readonly DependencyProperty SpacingProperty = DependencyProperty.RegisterAttached(
  22. "Spacing", typeof(double), typeof(PanelHelper), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsMeasure, OnSpacingChanged));
  23. public static double GetSpacing(DependencyObject obj)
  24. {
  25. return (double)obj.GetValue(SpacingProperty);
  26. }
  27. public static void SetSpacing(DependencyObject obj, double value)
  28. {
  29. obj.SetValue(SpacingProperty, value);
  30. }
  31. private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  32. {
  33. if (d is Panel panel)
  34. {
  35. panel.SizeChanged -= Panel_SizeChanged;
  36. panel.SizeChanged += Panel_SizeChanged;
  37. if (panel.IsLoaded)
  38. {
  39. SetPanelChildrenSpacing(panel, null);
  40. }
  41. else
  42. {
  43. panel.Loaded += SetPanelChildrenSpacing;
  44. }
  45. }
  46. }
  47. private static void Panel_SizeChanged(object sender, SizeChangedEventArgs e)
  48. {
  49. SetPanelChildrenSpacing(sender, null);
  50. }
  51. private static void SetPanelChildrenSpacing(object sender, RoutedEventArgs e)
  52. {
  53. var panel = (Panel)sender;
  54. panel.Loaded -= SetPanelChildrenSpacing;
  55. switch (panel)
  56. {
  57. case StackPanel stackPanel:
  58. SetStackPanelSpacing(stackPanel);
  59. break;
  60. case Grid grid:
  61. SetGridSpacing(grid);
  62. break;
  63. }
  64. }
  65. private static void SetHorizontalSpacing(SpacingType type, FrameworkElement element, double spacing, Thickness oldMargin)
  66. {
  67. switch (type)
  68. {
  69. case SpacingType.No:
  70. default:
  71. element.Margin = new Thickness(0, oldMargin.Top, 0, oldMargin.Bottom);
  72. break;
  73. case SpacingType.Start:
  74. element.Margin = new Thickness(spacing / 2, oldMargin.Top, 0, oldMargin.Bottom);
  75. break;
  76. case SpacingType.End:
  77. element.Margin = new Thickness(0, oldMargin.Top, spacing / 2, oldMargin.Bottom);
  78. break;
  79. case SpacingType.All:
  80. element.Margin = new Thickness(spacing / 2, oldMargin.Top, spacing / 2, oldMargin.Bottom);
  81. break;
  82. }
  83. }
  84. private static void SetVerticalSpacing(SpacingType type, FrameworkElement element, double spacing, Thickness oldMargin)
  85. {
  86. switch (type)
  87. {
  88. case SpacingType.No:
  89. default:
  90. element.Margin = new Thickness(oldMargin.Left, 0, oldMargin.Right, 0);
  91. break;
  92. case SpacingType.Start:
  93. element.Margin = new Thickness(oldMargin.Left, spacing / 2, oldMargin.Right, 0);
  94. break;
  95. case SpacingType.End:
  96. element.Margin = new Thickness(oldMargin.Left, 0, oldMargin.Right, spacing / 2);
  97. break;
  98. case SpacingType.All:
  99. element.Margin = new Thickness(oldMargin.Left, spacing / 2, oldMargin.Right, spacing / 2);
  100. break;
  101. }
  102. }
  103. // StackPanel
  104. private static void SetStackPanelSpacing(StackPanel stackPanel)
  105. {
  106. var children = stackPanel.Children.OfType<FrameworkElement>().Where(x => x.Visibility != Visibility.Collapsed).ToList();
  107. var count = children.Count;
  108. var index = 0;
  109. foreach (FrameworkElement element in children)
  110. {
  111. var spacing = GetSpacing(stackPanel);
  112. SpacingType type;
  113. if (index == 0)
  114. {
  115. type = SpacingType.End;
  116. }
  117. else if (index == count - 1)
  118. {
  119. type = SpacingType.Start;
  120. }
  121. else
  122. {
  123. type = SpacingType.All;
  124. }
  125. if (stackPanel.Orientation == Orientation.Horizontal)
  126. {
  127. SetHorizontalSpacing(type, element, spacing, new Thickness(0));
  128. }
  129. else
  130. {
  131. SetVerticalSpacing(type, element, spacing, new Thickness(0));
  132. }
  133. index++;
  134. }
  135. }
  136. // Grid
  137. private static void SetGridSpacing(Grid grid)
  138. {
  139. var children = grid.Children.OfType<FrameworkElement>().Where(x => x.Visibility != Visibility.Collapsed).ToList();
  140. foreach (FrameworkElement element in children)
  141. {
  142. var spacing = GetSpacing(grid);
  143. var oldMargin = element.Margin;
  144. // 水平间距
  145. var column = Grid.GetColumn(element);
  146. var columnSpan = Grid.GetColumnSpan(element);
  147. var gridColumns = grid.ColumnDefinitions.Count;
  148. SpacingType type;
  149. if (gridColumns == 0)
  150. {
  151. type = SpacingType.No;
  152. }
  153. else if (column == 0)
  154. {
  155. type = SpacingType.End;
  156. }
  157. else if (column + columnSpan == gridColumns)
  158. {
  159. type = SpacingType.Start;
  160. }
  161. else
  162. {
  163. type = SpacingType.All;
  164. }
  165. SetHorizontalSpacing(type, element, spacing, oldMargin);
  166. // 垂直间距
  167. oldMargin = element.Margin;
  168. var row = Grid.GetRow(element);
  169. var rowSpan = Grid.GetRowSpan(element);
  170. var gridRows = grid.RowDefinitions.Count;
  171. if (gridRows == 0)
  172. {
  173. type = SpacingType.No;
  174. }
  175. else if (row == 0)
  176. {
  177. type = SpacingType.End;
  178. }
  179. else if (row + rowSpan == gridRows)
  180. {
  181. type = SpacingType.Start;
  182. }
  183. else
  184. {
  185. type = SpacingType.All;
  186. }
  187. SetVerticalSpacing(type, element, spacing, oldMargin);
  188. }
  189. }
  190. }
  191. }
  192. /// <summary>
  193. /// 间隔类型
  194. /// </summary>
  195. internal enum SpacingType
  196. {
  197. /// <summary>
  198. /// 无间隔
  199. /// </summary>
  200. No = 0,
  201. /// <summary>
  202. /// 后面间隔
  203. /// </summary>
  204. Start,
  205. /// <summary>
  206. /// 后面间隔
  207. /// </summary>
  208. End,
  209. /// <summary>
  210. /// 前后间隔
  211. /// </summary>
  212. All,
  213. }