125 lines
5.2 KiB
C#
125 lines
5.2 KiB
C#
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
|
||
}
|