Files
ShrlAlgoToolkit/Melskin/Controls/StepBar.xaml.cs
2026-02-22 20:03:42 +08:00

125 lines
5.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Melskin.Controls
{
public class StepBar : ItemsControl
{
// 使用 StepProgress 代替 SelectedIndex允许值范围 0 到 Items.Count
public static readonly DependencyProperty StepProgressProperty =
DependencyProperty.Register("StepProgress", typeof(int), typeof(StepBar),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnStepProgressChanged));
public int StepProgress
{
get => (int)GetValue(StepProgressProperty);
set => SetValue(StepProgressProperty, value);
}
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(StepBar),
new PropertyMetadata(Orientation.Horizontal));
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
static StepBar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(StepBar), new FrameworkPropertyMetadata(typeof(StepBar)));
}
private static void OnStepProgressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is StepBar bar) bar.UpdateItemsStatus();
}
protected override DependencyObject GetContainerForItemOverride() => new StepBarItem();
protected override bool IsItemItsOwnContainerOverride(object item) => item is StepBarItem;
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
UpdateItemsStatus();
}
internal void UpdateItemsStatus()
{
for (int i = 0; i < Items.Count; i++)
{
if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem container)
{
container.Index = i + 1;
container.IsLast = (i == Items.Count - 1);
container.Orientation = this.Orientation;
// 核心逻辑:
// i < Progress -> 已完成 (Completed)
// i == Progress -> 进行中 (Active)
// i > Progress -> 等待 (Waiting)
if (i < StepProgress)
container.Status = StepStatus.Completed;
else if (i == StepProgress)
container.Status = StepStatus.Active;
else
container.Status = StepStatus.Waiting;
}
}
}
}
public class StepBarItem : ContentControl
{
public static readonly DependencyProperty StatusProperty = DependencyProperty.Register("Status", typeof(StepStatus), typeof(StepBarItem), new PropertyMetadata(StepStatus.Waiting));
public StepStatus Status { get => (StepStatus)GetValue(StatusProperty); set => SetValue(StatusProperty, value); }
public static readonly DependencyProperty IndexProperty = DependencyProperty.Register("Index", typeof(int), typeof(StepBarItem), new PropertyMetadata(1));
public int Index { get => (int)GetValue(IndexProperty); set => SetValue(IndexProperty, value); }
public static readonly DependencyProperty IsLastProperty = DependencyProperty.Register("IsLast", typeof(bool), typeof(StepBarItem), new PropertyMetadata(false));
public bool IsLast { get => (bool)GetValue(IsLastProperty); set => SetValue(IsLastProperty, value); }
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(StepBarItem), new PropertyMetadata(Orientation.Horizontal));
public Orientation Orientation { get => (Orientation)GetValue(OrientationProperty); set => SetValue(OrientationProperty, value); }
static StepBarItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(StepBarItem), new FrameworkPropertyMetadata(typeof(StepBarItem)));
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
var parent = ItemsControl.ItemsControlFromItemContainer(this) as StepBar;
if (parent != null)
{
int myIndex = parent.ItemContainerGenerator.IndexFromContainer(this);
// 点击逻辑:
// 1. 如果点的是当前正在进行的步 -> 完成这一步,进度+1
// 2. 如果点的是已经完成的步 -> 回退到那一步
// 3. 如果点的是还没开始的步 -> 直接跳到那一步
if (parent.StepProgress == myIndex)
{
parent.StepProgress = myIndex + 1;
}
else
{
parent.StepProgress = myIndex;
}
}
}
}
}
public enum StepStatus
{
Completed,
Active,
Waiting
}