终端一体化运控平台
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.
 
 
 

201 line
5.6 KiB

  1. using BPASmartClient.MilkWithTea.Data;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Media;
  7. namespace BPASmartClient.MilkWithTea.Control;
  8. public class TabPanel : Panel
  9. {
  10. private int _itemCount;
  11. /// <summary>
  12. /// 是否可以更新
  13. /// </summary>
  14. internal bool CanUpdate = true;
  15. /// <summary>
  16. /// 选项卡字典
  17. /// </summary>
  18. internal Dictionary<int, TabItem> ItemDic = new();
  19. public static readonly DependencyPropertyKey FluidMoveDurationPropertyKey =
  20. DependencyProperty.RegisterReadOnly("FluidMoveDuration", typeof(Duration), typeof(TabPanel),
  21. new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(0))));
  22. /// <summary>
  23. /// 流式行为持续时间
  24. /// </summary>
  25. public static readonly DependencyProperty FluidMoveDurationProperty =
  26. FluidMoveDurationPropertyKey.DependencyProperty;
  27. /// <summary>
  28. /// 流式行为持续时间
  29. /// </summary>
  30. public Duration FluidMoveDuration
  31. {
  32. get => (Duration) GetValue(FluidMoveDurationProperty);
  33. set => SetValue(FluidMoveDurationProperty, value);
  34. }
  35. /// <summary>
  36. /// 是否将标签填充
  37. /// </summary>
  38. public static readonly DependencyProperty IsTabFillEnabledProperty = DependencyProperty.Register(
  39. "IsTabFillEnabled", typeof(bool), typeof(TabPanel), new PropertyMetadata(ValueBoxes.FalseBox));
  40. /// <summary>
  41. /// 是否将标签填充
  42. /// </summary>
  43. public bool IsTabFillEnabled
  44. {
  45. get => (bool) GetValue(IsTabFillEnabledProperty);
  46. set => SetValue(IsTabFillEnabledProperty, ValueBoxes.BooleanBox(value));
  47. }
  48. /// <summary>
  49. /// 标签宽度
  50. /// </summary>
  51. public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register(
  52. "TabItemWidth", typeof(double), typeof(TabPanel), new PropertyMetadata(200.0));
  53. /// <summary>
  54. /// 标签宽度
  55. /// </summary>
  56. public double TabItemWidth
  57. {
  58. get => (double) GetValue(TabItemWidthProperty);
  59. set => SetValue(TabItemWidthProperty, value);
  60. }
  61. /// <summary>
  62. /// 标签高度
  63. /// </summary>
  64. public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register(
  65. "TabItemHeight", typeof(double), typeof(TabPanel), new PropertyMetadata(30.0));
  66. /// <summary>
  67. /// 标签高度
  68. /// </summary>
  69. public double TabItemHeight
  70. {
  71. get => (double) GetValue(TabItemHeightProperty);
  72. set => SetValue(TabItemHeightProperty, value);
  73. }
  74. /// <summary>
  75. /// 是否可以强制更新
  76. /// </summary>
  77. internal bool ForceUpdate;
  78. private Size _oldSize;
  79. /// <summary>
  80. /// 是否已经加载
  81. /// </summary>
  82. private bool _isLoaded;
  83. protected override Size MeasureOverride(Size constraint)
  84. {
  85. if ((_itemCount == InternalChildren.Count || !CanUpdate) && !ForceUpdate && !IsTabFillEnabled) return _oldSize;
  86. constraint.Height = TabItemHeight;
  87. _itemCount = InternalChildren.Count;
  88. var size = new Size();
  89. ItemDic.Clear();
  90. var count = InternalChildren.Count;
  91. if (count == 0)
  92. {
  93. _oldSize = new Size();
  94. return _oldSize;
  95. }
  96. constraint.Width += InternalChildren.Count;
  97. var itemWidth = .0;
  98. var arr = new int[count];
  99. if (!IsTabFillEnabled)
  100. {
  101. itemWidth = TabItemWidth;
  102. }
  103. else
  104. {
  105. if (TemplatedParent is TabControl tabControl)
  106. {
  107. arr = DivideInt2Arr((int) tabControl.ActualWidth + InternalChildren.Count, count);
  108. }
  109. }
  110. for (var index = 0; index < count; index++)
  111. {
  112. if (IsTabFillEnabled)
  113. {
  114. itemWidth = arr[index];
  115. }
  116. if (InternalChildren[index] is TabItem tabItem)
  117. {
  118. tabItem.RenderTransform = new TranslateTransform();
  119. tabItem.MaxWidth = itemWidth;
  120. var rect = new Rect
  121. {
  122. X = size.Width - tabItem.BorderThickness.Left,
  123. Width = itemWidth,
  124. Height = TabItemHeight
  125. };
  126. tabItem.Arrange(rect);
  127. tabItem.ItemWidth = itemWidth - tabItem.BorderThickness.Left;
  128. tabItem.CurrentIndex = index;
  129. tabItem.TargetOffsetX = 0;
  130. ItemDic[index] = tabItem;
  131. size.Width += tabItem.ItemWidth;
  132. }
  133. }
  134. size.Height = constraint.Height;
  135. _oldSize = size;
  136. return _oldSize;
  137. }
  138. /// <summary>
  139. /// 平分一个整数到一个数组中
  140. /// </summary>
  141. /// <param name="num"></param>
  142. /// <param name="count"></param>
  143. /// <returns></returns>
  144. public static int[] DivideInt2Arr(int num, int count)
  145. {
  146. var arr = new int[count];
  147. var div = num / count;
  148. var rest = num % count;
  149. for (var i = 0; i < count; i++)
  150. {
  151. arr[i] = div;
  152. }
  153. for (var i = 0; i < rest; i++)
  154. {
  155. arr[i] += 1;
  156. }
  157. return arr;
  158. }
  159. public TabPanel()
  160. {
  161. Loaded += (s, e) =>
  162. {
  163. if (_isLoaded) return;
  164. ForceUpdate = true;
  165. Measure(new Size(DesiredSize.Width, ActualHeight));
  166. ForceUpdate = false;
  167. foreach (var item in ItemDic.Values)
  168. {
  169. item.TabPanel = this;
  170. }
  171. _isLoaded = true;
  172. };
  173. }
  174. }