2025-10-17 14:18:01 +08:00

136 lines
4.6 KiB
C#

using Emgu.CV.Flann;
using HandyControl.Controls;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wpf_AiSportsMicrospace.MyUserControl
{
public partial class BeatScrollDots : UserControl
{
public ObservableCollection<DotItem> Dots { get; set; } = new ObservableCollection<DotItem>();
public BeatScrollDots()
{
InitializeComponent();
DataContext = this;
}
public int DotCount
{
get => (int)GetValue(DotCountProperty);
set => SetValue(DotCountProperty, value);
}
public static readonly DependencyProperty DotCountProperty =
DependencyProperty.Register(nameof(DotCount), typeof(int), typeof(BeatScrollDots),
new PropertyMetadata(0, OnDotCountChanged));
private static void OnDotCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is BeatScrollDots ctrl)
ctrl.GenerateDots();
}
private void GenerateDots()
{
Dots.Clear();
for (int i = 0; i < DotCount; i++)
Dots.Add(new DotItem { IsSelected = false });
}
public void SetSelected(int index, bool selected)
{
if (index >= 0 && index < Dots.Count)
Dots[index].IsSelected = selected;
}
public Thickness DotSpacing
{
get => (Thickness)GetValue(DotSpacingProperty);
set => SetValue(DotSpacingProperty, value);
}
public static readonly DependencyProperty DotSpacingProperty =
DependencyProperty.Register(nameof(DotSpacing), typeof(Thickness), typeof(BeatScrollDots), new PropertyMetadata(new Thickness(5, 0, 5, 0)));
public void ScrollToDotCenter(int index, bool mirror = false)
{
if (scrollViewer == null || Dots.Count == 0) return;
double step = 20 + DotSpacing.Left + DotSpacing.Right;
double totalWidth = Dots.Count * step;
double dotCenter = index * step + step / 2;
double targetOffset = !mirror
? dotCenter - scrollViewer.ActualWidth / 2
: totalWidth - dotCenter - scrollViewer.ActualWidth / 2;
targetOffset = System.Math.Max(0, System.Math.Min(targetOffset, scrollViewer.ScrollableWidth));
scrollViewer.ScrollToHorizontalOffset(targetOffset);
}
public void UpdateSpacingForCount(int count)
{
if (count <= 0) count = 1;
double spacing = (ActualWidth / count) - 20;
if (spacing < 2) spacing = 2;
DotSpacing = new Thickness(spacing / 2, 0, spacing / 2, 0);
}
public Dictionary<int, List<double>> MusicBeatsDic
{
get => (Dictionary<int, List<double>>)GetValue(MusicBeatsDicProperty);
set => SetValue(MusicBeatsDicProperty, value);
}
public static readonly DependencyProperty MusicBeatsDicProperty =
DependencyProperty.Register(nameof(MusicBeatsDic), typeof(Dictionary<int, List<double>>), typeof(BeatScrollDots),
new PropertyMetadata(null, OnMusicBeatsDicChanged));
private static void OnMusicBeatsDicChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is BeatScrollDots ctrl)
{
// 可选:根据第一个 key 初始化 DotCount
if (ctrl.MusicBeatsDic != null && ctrl.MusicBeatsDic.Any())
{
int firstKey = ctrl.MusicBeatsDic.Keys.Min();
ctrl.DotCount = ctrl.MusicBeatsDic[firstKey].Count;
ctrl.UpdateSpacingForCount(ctrl.DotCount);
}
}
}
}
public class DotItem : INotifyPropertyChanged
{
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected != value)
{
_isSelected = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected)));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}