TabPanel.cs 5.1 KB

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