|
|
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;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 보기용 표시: "101–150 / 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));
|
|
|
}
|
|
|
}
|