feat: 페이지 버튼 추가

prototype
HyungJune Kim 7 months ago
parent 90bcf08256
commit 289316a71f

@ -49,4 +49,33 @@ namespace SmartAquaViewer.Classes
int.TryParse(value?.ToString(), out var v) ? Math.Max(1, v) - 1 : 0;
}
public class PageIndexToDisplayConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is int idx)
return (idx + 1).ToString(); // 0 -> 1, 1 -> 2 ...
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (int.TryParse(value?.ToString(), out int display))
return display - 1; // 1 -> 0
return 0;
}
}
public class CurrentPageEqualsConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length >= 2 && values[0] is int buttonIndex && values[1] is int currentIndex)
return buttonIndex == currentIndex;
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> throw new NotImplementedException();
}
}

@ -50,8 +50,10 @@ namespace SmartAquaViewer.Model
{
string cctvListPath = Utils.Instance.GetDataFileContentPath(Constants.DataFiles.CCTV_LIST);
if (!File.Exists(cctvListPath))
{
CreateAndSetMockUpCCTVInfoList(cctvListPath);
return;
}
string jsonString = File.ReadAllText(cctvListPath);
var cctvInfoList = JsonConvert.DeserializeObject<List<CCTVInfo>>(jsonString) ?? new List<CCTVInfo>();

@ -14,6 +14,8 @@
<UserControl.Resources>
<classes:InverseBoolConverter x:Key="InverseBoolConverter"/>
<classes:OneBasedConverter x:Key="OneBasedConverter"/>
<classes:PageIndexToDisplayConverter x:Key="PageIndexToDisplayConverter"/>
<classes:CurrentPageEqualsConverter x:Key="CurrentPageEqualsConverter"/>
</UserControl.Resources>
<Border BorderBrush="#2d374c" BorderThickness="2">
@ -178,13 +180,51 @@
<md:PackIcon Kind="ChevronLeft"/>
</Button>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="8,0">
<TextBlock Margin="0 5" Foreground="White"
Text="{Binding PageIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource OneBasedConverter}}"/>
<TextBlock Text="{Binding TotalPages, StringFormat=/ {0}}"
Foreground="White" VerticalAlignment="Center" Margin="6,0,0,0"/>
</StackPanel>
<ItemsControl ItemsSource="{Binding PageNumbers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="2"
Padding="6,2"
Command="{Binding DataContext.GoToPageCommand,
RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}">
<Button.Content>
<Binding Converter="{StaticResource PageIndexToDisplayConverter}" />
</Button.Content>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="BorderThickness" Value="1" />
<!-- 🔹 현재 페이지면 강조 -->
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource CurrentPageEqualsConverter}">
<!--현재 버튼의 인덱스-->
<Binding />
<!--ViewModel의 PageIndex-->
<Binding Path="DataContext.PageIndex"
RelativeSource="{RelativeSource AncestorType=ItemsControl}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="#FF007ACC" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Command="{Binding NextPageCommand}"
Style="{StaticResource MaterialDesignFlatLightBgButton}" Margin="4,0">

@ -14,6 +14,8 @@
<UserControl.Resources>
<classes:InverseBoolConverter x:Key="InverseBoolConverter"/>
<classes:OneBasedConverter x:Key="OneBasedConverter"/>
<classes:PageIndexToDisplayConverter x:Key="PageIndexToDisplayConverter"/>
<classes:CurrentPageEqualsConverter x:Key="CurrentPageEqualsConverter"/>
</UserControl.Resources>
<Border BorderBrush="#2d374c" BorderThickness="2">
@ -178,13 +180,51 @@
<md:PackIcon Kind="ChevronLeft"/>
</Button>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="8,0">
<TextBlock Margin="0 5" Foreground="White"
Text="{Binding PageIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource OneBasedConverter}}"/>
<TextBlock Text="{Binding TotalPages, StringFormat=/ {0}}"
Foreground="White" VerticalAlignment="Center" Margin="6,0,0,0"/>
</StackPanel>
<ItemsControl ItemsSource="{Binding PageNumbers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="2"
Padding="6,2"
Command="{Binding DataContext.GoToPageCommand,
RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}">
<Button.Content>
<Binding Converter="{StaticResource PageIndexToDisplayConverter}" />
</Button.Content>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="BorderThickness" Value="1" />
<!-- 🔹 현재 페이지면 강조 -->
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource CurrentPageEqualsConverter}">
<!--현재 버튼의 인덱스-->
<Binding />
<!--ViewModel의 PageIndex-->
<Binding Path="DataContext.PageIndex"
RelativeSource="{RelativeSource AncestorType=ItemsControl}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="#FF007ACC" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Command="{Binding NextPageCommand}"
Style="{StaticResource MaterialDesignFlatLightBgButton}" Margin="4,0">

@ -16,6 +16,8 @@
<classes:EnumEqualsConverter x:Key="EnumEqualsConverter"/>
<classes:BoolToPowerConverter x:Key="BoolToPowerConverter"/>
<classes:OneBasedConverter x:Key="OneBasedConverter"/>
<classes:PageIndexToDisplayConverter x:Key="PageIndexToDisplayConverter"/>
<classes:CurrentPageEqualsConverter x:Key="CurrentPageEqualsConverter"/>
</UserControl.Resources>
<Border BorderBrush="#2d374c" BorderThickness="2">
@ -362,14 +364,54 @@
<md:PackIcon Kind="ChevronLeft"/>
</Button>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="8,0">
<TextBlock Margin="0 5" Foreground="White"
Text="{Binding TanksPager.PageIndex, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource OneBasedConverter}}"/>
<TextBlock Text="{Binding TanksPager.TotalPages, StringFormat=/ {0}}"
Foreground="White" VerticalAlignment="Center" Margin="6,0,0,0"/>
</StackPanel>
<ItemsControl DataContext="{Binding TanksPager}"
ItemsSource="{Binding PageNumbers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="2"
Padding="6,2"
Command="{Binding DataContext.GoToPageCommand,
RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}">
<Button.Content>
<!-- 각 아이템은 int(0,1,2,...) 이므로 그대로 컨버터 -->
<Binding Converter="{StaticResource PageIndexToDisplayConverter}" />
</Button.Content>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="BorderThickness" Value="1" />
<!-- 현재 페이지면 강조 -->
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource CurrentPageEqualsConverter}">
<!-- 현재 버튼의 인덱스 (각 아이템, int) -->
<Binding />
<!-- TanksPager.PageIndex -->
<Binding Path="DataContext.PageIndex"
RelativeSource="{RelativeSource AncestorType=ItemsControl}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="#FF007ACC" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Command="{Binding TanksPager.NextPageCommand}"
Style="{StaticResource MaterialDesignFlatLightBgButton}" Margin="4,0">
@ -405,13 +447,51 @@
<md:PackIcon Kind="ChevronLeft"/>
</Button>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="8,0">
<TextBlock Margin="0 5" Foreground="White"
Text="{Binding PageIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource OneBasedConverter}}"/>
<TextBlock Text="{Binding TotalPages, StringFormat=/ {0}}"
Foreground="White" VerticalAlignment="Center" Margin="6,0,0,0"/>
</StackPanel>
<ItemsControl ItemsSource="{Binding PageNumbers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="2"
Padding="6,2"
Command="{Binding DataContext.GoToPageCommand,
RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}">
<Button.Content>
<Binding Converter="{StaticResource PageIndexToDisplayConverter}" />
</Button.Content>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="BorderThickness" Value="1" />
<!-- 🔹 현재 페이지면 강조 -->
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource CurrentPageEqualsConverter}">
<!--현재 버튼의 인덱스-->
<Binding />
<!--ViewModel의 PageIndex-->
<Binding Path="DataContext.PageIndex"
RelativeSource="{RelativeSource AncestorType=ItemsControl}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="#FF007ACC" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Command="{Binding NextPageCommand}"
Style="{StaticResource MaterialDesignFlatLightBgButton}" Margin="4,0">

@ -1,6 +1,5 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;

@ -1,13 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SmartAquaViewer.Controls;
using System.Windows.Input;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using SmartAquaViewer.Controls;
namespace SmartAquaViewer.ViewModel
{
@ -32,7 +27,16 @@ namespace SmartAquaViewer.ViewModel
public int PageSize
{
get => _pageSize;
set { if (_pageSize != value) { _pageSize = value; PageIndex = 0; OnPropertyChanged(); RebuildPage(); } }
set
{
if (_pageSize != value)
{
_pageSize = value;
PageIndex = 0;
OnPropertyChanged();
RebuildPage();
}
}
}
private int _pageIndex; // 0-based
@ -48,6 +52,38 @@ namespace SmartAquaViewer.ViewModel
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
{
@ -65,6 +101,19 @@ namespace SmartAquaViewer.ViewModel
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);
@ -85,6 +134,7 @@ namespace SmartAquaViewer.ViewModel
OnPropertyChanged(nameof(TotalCount));
OnPropertyChanged(nameof(TotalPages));
OnPropertyChanged(nameof(PageStatus));
OnPropertyChanged(nameof(PageNumbers));
// 버튼 CanExecute 즉시 반영
CommandManager.InvalidateRequerySuggested();

Loading…
Cancel
Save