StepBar.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. using System;
  2. using System.ComponentModel;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Controls.Primitives;
  6. using System.Windows.Input;
  7. using System.Windows.Media;
  8. using HandyControl.Data;
  9. using HandyControl.Interactivity;
  10. using HandyControl.Tools;
  11. namespace HandyControl.Controls;
  12. [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(StepBarItem))]
  13. [DefaultEvent("StepChanged")]
  14. [TemplatePart(Name = ElementProgressBarBack, Type = typeof(ProgressBar))]
  15. public class StepBar : ItemsControl
  16. {
  17. private const string ElementProgressBarBack = "PART_ProgressBarBack";
  18. private ProgressBar _progressBarBack;
  19. private int _oriStepIndex = -1;
  20. public StepBar()
  21. {
  22. CommandBindings.Add(new CommandBinding(ControlCommands.Next, (_, _) => Next()));
  23. CommandBindings.Add(new CommandBinding(ControlCommands.Prev, (_, _) => Prev()));
  24. ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
  25. AddHandler(SelectableItem.SelectedEvent, new RoutedEventHandler(OnStepBarItemSelected));
  26. }
  27. private void OnStepBarItemSelected(object sender, RoutedEventArgs e)
  28. {
  29. if (!IsMouseSelectable)
  30. {
  31. return;
  32. }
  33. if (e.OriginalSource is StepBarItem item)
  34. {
  35. SetCurrentValue(StepIndexProperty, item.Index - 1);
  36. }
  37. }
  38. private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
  39. {
  40. if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
  41. {
  42. return;
  43. }
  44. int count = Items.Count;
  45. InvalidateVisual();
  46. _progressBarBack.Maximum = count - 1;
  47. _progressBarBack.Value = StepIndex;
  48. if (count <= 0)
  49. {
  50. return;
  51. }
  52. for (int i = 0; i < count; i++)
  53. {
  54. if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem stepBarItem)
  55. {
  56. stepBarItem.Index = i + 1;
  57. }
  58. }
  59. if (_oriStepIndex > 0)
  60. {
  61. StepIndex = _oriStepIndex;
  62. _oriStepIndex = -1;
  63. }
  64. else
  65. {
  66. OnStepIndexChanged(StepIndex);
  67. }
  68. }
  69. protected override bool IsItemItsOwnContainerOverride(object item) => item is StepBarItem;
  70. protected override DependencyObject GetContainerForItemOverride() => new StepBarItem();
  71. /// <summary>
  72. /// 步骤改变事件
  73. /// </summary>
  74. public static readonly RoutedEvent StepChangedEvent =
  75. EventManager.RegisterRoutedEvent("StepChanged", RoutingStrategy.Bubble,
  76. typeof(EventHandler<FunctionEventArgs<int>>), typeof(StepBar));
  77. /// <summary>
  78. /// 步骤改变事件
  79. /// </summary>
  80. [Category("Behavior")]
  81. public event EventHandler<FunctionEventArgs<int>> StepChanged
  82. {
  83. add => AddHandler(StepChangedEvent, value);
  84. remove => RemoveHandler(StepChangedEvent, value);
  85. }
  86. public static readonly DependencyProperty StepIndexProperty = DependencyProperty.Register(
  87. nameof(StepIndex), typeof(int), typeof(StepBar), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
  88. FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnStepIndexChanged, CoerceStepIndex));
  89. private static object CoerceStepIndex(DependencyObject d, object baseValue)
  90. {
  91. var ctl = (StepBar) d;
  92. int stepIndex = (int) baseValue;
  93. if (ctl.Items.Count == 0 && stepIndex > 0)
  94. {
  95. ctl._oriStepIndex = stepIndex;
  96. return ValueBoxes.Int0Box;
  97. }
  98. return stepIndex < 0
  99. ? ValueBoxes.Int0Box
  100. : stepIndex >= ctl.Items.Count
  101. ? ctl.Items.Count == 0 ? 0 : ctl.Items.Count - 1
  102. : baseValue;
  103. }
  104. private static void OnStepIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  105. {
  106. var ctl = (StepBar) d;
  107. ctl.OnStepIndexChanged((int) e.NewValue);
  108. }
  109. private void OnStepIndexChanged(int stepIndex)
  110. {
  111. for (int i = 0; i < stepIndex; i++)
  112. {
  113. if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem stepItemFinished)
  114. {
  115. stepItemFinished.Status = StepStatus.Complete;
  116. }
  117. }
  118. for (int i = stepIndex + 1; i < Items.Count; i++)
  119. {
  120. if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem stepItemFinished)
  121. {
  122. stepItemFinished.Status = StepStatus.Waiting;
  123. }
  124. }
  125. if (ItemContainerGenerator.ContainerFromIndex(stepIndex) is StepBarItem stepItemSelected)
  126. {
  127. stepItemSelected.Status = StepStatus.UnderWay;
  128. }
  129. _progressBarBack?.BeginAnimation(RangeBase.ValueProperty, AnimationHelper.CreateAnimation(stepIndex));
  130. RaiseEvent(new FunctionEventArgs<int>(StepChangedEvent, this)
  131. {
  132. Info = stepIndex
  133. });
  134. }
  135. public int StepIndex
  136. {
  137. get => (int) GetValue(StepIndexProperty);
  138. set => SetValue(StepIndexProperty, value);
  139. }
  140. public static readonly DependencyProperty DockProperty = DependencyProperty.Register(
  141. nameof(Dock), typeof(Dock), typeof(StepBar), new PropertyMetadata(Dock.Top));
  142. public Dock Dock
  143. {
  144. get => (Dock) GetValue(DockProperty);
  145. set => SetValue(DockProperty, value);
  146. }
  147. public static readonly DependencyProperty IsMouseSelectableProperty = DependencyProperty.Register(
  148. nameof(IsMouseSelectable), typeof(bool), typeof(StepBar), new PropertyMetadata(ValueBoxes.FalseBox));
  149. public bool IsMouseSelectable
  150. {
  151. get => (bool) GetValue(IsMouseSelectableProperty);
  152. set => SetValue(IsMouseSelectableProperty, ValueBoxes.BooleanBox(value));
  153. }
  154. public override void OnApplyTemplate()
  155. {
  156. base.OnApplyTemplate();
  157. _progressBarBack = GetTemplateChild(ElementProgressBarBack) as ProgressBar;
  158. }
  159. protected override void OnRender(DrawingContext drawingContext)
  160. {
  161. base.OnRender(drawingContext);
  162. int colCount = Items.Count;
  163. if (_progressBarBack == null || colCount <= 0)
  164. {
  165. return;
  166. }
  167. if (Dock is Dock.Top or Dock.Bottom)
  168. {
  169. _progressBarBack.Width = (colCount - 1) * (ActualWidth / colCount);
  170. }
  171. else
  172. {
  173. _progressBarBack.Height = (colCount - 1) * (ActualHeight / colCount);
  174. }
  175. }
  176. public void Next() => StepIndex++;
  177. public void Prev() => StepIndex--;
  178. }