using System; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Media; using HandyControl.Data; using HandyControl.Interactivity; using HandyControl.Tools; namespace HandyControl.Controls { [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(StepBarItem))] [DefaultEvent("StepChanged")] [TemplatePart(Name = ElementProgressBarBack, Type = typeof(ProgressBar))] public class StepBar : ItemsControl { private ProgressBar _progressBarBack; private int _oriStepIndex = -1; #region Constants private const string ElementProgressBarBack = "PART_ProgressBarBack"; #endregion Constants public StepBar() { CommandBindings.Add(new CommandBinding(ControlCommands.Next, (s, e) => Next())); CommandBindings.Add(new CommandBinding(ControlCommands.Prev, (s, e) => Prev())); ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged; } private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e) { if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) { var count = Items.Count; if (count <= 0) return; for (var i = 0; i < count; i++) { if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem stepBarItem) { stepBarItem.Index = i + 1; } } if (_oriStepIndex > 0) { StepIndex = _oriStepIndex; _oriStepIndex = -1; } else { OnStepIndexChanged(StepIndex); } } } protected override bool IsItemItsOwnContainerOverride(object item) => item is StepBarItem; protected override DependencyObject GetContainerForItemOverride() => new StepBarItem(); /// /// 步骤改变事件 /// public static readonly RoutedEvent StepChangedEvent = EventManager.RegisterRoutedEvent("StepChanged", RoutingStrategy.Bubble, typeof(EventHandler>), typeof(StepBar)); /// /// 步骤改变事件 /// [Category("Behavior")] public event EventHandler> StepChanged { add => AddHandler(StepChangedEvent, value); remove => RemoveHandler(StepChangedEvent, value); } public static readonly DependencyProperty StepIndexProperty = DependencyProperty.Register( "StepIndex", typeof(int), typeof(StepBar), new FrameworkPropertyMetadata(ValueBoxes.Int0Box, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnStepIndexChanged, CoerceStepIndex)); private static object CoerceStepIndex(DependencyObject d, object basevalue) { var ctl = (StepBar)d; var stepIndex = (int) basevalue; if (ctl.Items.Count == 0 && stepIndex > 0) { ctl._oriStepIndex = stepIndex; return ValueBoxes.Int0Box; } return stepIndex < 0 ? ValueBoxes.Int0Box : stepIndex >= ctl.Items.Count ? ctl.Items.Count == 0 ? 0 : ctl.Items.Count - 1 : basevalue; } private static void OnStepIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var ctl = (StepBar) d; ctl.OnStepIndexChanged((int)e.NewValue); } private void OnStepIndexChanged(int stepIndex) { for (var i = 0; i < stepIndex; i++) { if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem stepItemFinished) { stepItemFinished.Status = StepStatus.Complete; } } for (var i = stepIndex + 1; i < Items.Count; i++) { if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem stepItemFinished) { stepItemFinished.Status = StepStatus.Waiting; } } if (ItemContainerGenerator.ContainerFromIndex(stepIndex) is StepBarItem stepItemSelected) stepItemSelected.Status = StepStatus.UnderWay; _progressBarBack?.BeginAnimation(RangeBase.ValueProperty, AnimationHelper.CreateAnimation(stepIndex)); RaiseEvent(new FunctionEventArgs(StepChangedEvent, this) { Info = stepIndex }); } public int StepIndex { get => (int)GetValue(StepIndexProperty); set => SetValue(StepIndexProperty, value); } public static readonly DependencyProperty DockProperty = DependencyProperty.Register( "Dock", typeof(Dock), typeof(StepBar), new PropertyMetadata(Dock.Top)); public Dock Dock { get => (Dock)GetValue(DockProperty); set => SetValue(DockProperty, value); } public override void OnApplyTemplate() { base.OnApplyTemplate(); _progressBarBack = GetTemplateChild(ElementProgressBarBack) as ProgressBar; } protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); var colCount = Items.Count; if (_progressBarBack == null || colCount <= 0) return; _progressBarBack.Maximum = colCount - 1; _progressBarBack.Value = StepIndex; if (Dock == Dock.Top || Dock == Dock.Bottom) { _progressBarBack.Width = (colCount - 1) * (ActualWidth / colCount); } else { _progressBarBack.Height = (colCount - 1) * (ActualHeight / colCount); } } public void Next() => StepIndex++; public void Prev() => StepIndex--; } }