You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SmartAquaViewer/SmartAquaViewer/ViewModel/PagingViewModelBase.cs

148 lines
4.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using SmartAquaViewer.Controls;
namespace SmartAquaViewer.ViewModel
{
public interface IPager
{
int PageSize { get; set; }
int PageIndex { get; set; }
int TotalPages { get; }
string PageStatus { get; }
ICommand FirstPageCommand { get; }
ICommand PrevPageCommand { get; }
ICommand NextPageCommand { get; }
ICommand LastPageCommand { get; }
}
public class PagingViewModelBase<T> : INotifyPropertyChanged, IPager
{
public ObservableCollection<T> Items { get; } = new();
private int _pageSize = 10;
public int PageSize
{
get => _pageSize;
set
{
if (_pageSize != value)
{
_pageSize = value;
PageIndex = 0;
OnPropertyChanged();
RebuildPage();
}
}
}
private int _pageIndex; // 0-based
public int PageIndex
{
get => _pageIndex;
set { if (_pageIndex != value) { _pageIndex = Math.Max(0, Math.Min(value, TotalPages - 1)); OnPropertyChanged(nameof(PageIndex)); RebuildPage(); } }
}
public int TotalCount => Items.Count;
public int TotalPages => Math.Max(1, (int)Math.Ceiling(TotalCount / (double)PageSize));
private readonly ObservableCollection<T> _pagedItems = new();
public ReadOnlyObservableCollection<T> PagedItems { get; }
private int _pageGroupSize = 5;
public int PageGroupSize
{
get => _pageGroupSize;
set
{
if (_pageGroupSize != value)
{
_pageGroupSize = value;
OnPropertyChanged();
OnPropertyChanged(nameof(PageNumbers));
}
}
}
// 🔹 현재 그룹에 표시할 페이지 인덱스들 (0-based)
public IEnumerable<int> PageNumbers
{
get
{
if (TotalPages <= 0) yield break;
// 현재 그룹: ex) 0~4, 5~9, ...
var groupIndex = PageIndex / PageGroupSize;
var start = groupIndex * PageGroupSize;
var end = Math.Min(start + PageGroupSize - 1, TotalPages - 1);
for (int i = start; i <= end; i++)
yield return i;
}
}
// 보기용 표시: "101150 / 4,327 (3/87)"
public string PageStatus
{
get
{
if (TotalCount == 0) return "0 / 0 (0/0)";
var start = PageIndex * PageSize + 1;
var end = Math.Min((PageIndex + 1) * PageSize, TotalCount);
return $"{start}{end} / {TotalCount:N0} ({PageIndex + 1}/{TotalPages})";
}
}
public ICommand FirstPageCommand => new RelayCommand(_ => PageIndex = 0, _ => PageIndex > 0);
public ICommand PrevPageCommand => new RelayCommand(_ => PageIndex--, _ => PageIndex > 0);
public ICommand NextPageCommand => new RelayCommand(_ => PageIndex++, _ => PageIndex < TotalPages - 1);
public ICommand LastPageCommand => new RelayCommand(_ => PageIndex = TotalPages - 1, _ => PageIndex < TotalPages - 1);
public ICommand GoToPageCommand => new RelayCommand(
p =>
{
if (p is int idx)
PageIndex = idx;
},
p =>
{
if (p is int idx)
return idx >= 0 && idx < TotalPages;
return false;
});
public PagingViewModelBase()
{
PagedItems = new ReadOnlyObservableCollection<T>(_pagedItems);
Items.CollectionChanged += (_, __) => RebuildPage(); // 원본이 바뀌면 재구성
RebuildPage();
}
private void RebuildPage()
{
// 현재 페이지 구간
var slice = Items.Skip(PageIndex * PageSize).Take(PageSize).ToList();
// 🔹 ObservableCollection 동기화 (Clear/Add)
_pagedItems.Clear();
foreach (var item in slice) _pagedItems.Add(item);
// 숫자/상태 텍스트 갱신
OnPropertyChanged(nameof(TotalCount));
OnPropertyChanged(nameof(TotalPages));
OnPropertyChanged(nameof(PageStatus));
OnPropertyChanged(nameof(PageNumbers));
// 버튼 CanExecute 즉시 반영
CommandManager.InvalidateRequerySuggested();
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? name = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}