253 lines
7.2 KiB
C#
253 lines
7.2 KiB
C#
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.ComponentModel;
|
|||
|
using System.Reflection;
|
|||
|
using Avalonia;
|
|||
|
using Avalonia.Controls;
|
|||
|
using Avalonia.Data;
|
|||
|
using Avalonia.Interactivity;
|
|||
|
using Avalonia.Layout;
|
|||
|
using Avalonia.Markup.Xaml;
|
|||
|
using Avalonia.Media;
|
|||
|
using Avalonia.Threading;
|
|||
|
using DynamicData;
|
|||
|
using DispenserCommon.Atrributes;
|
|||
|
using DispenserCommon.Utils;
|
|||
|
using Masuit.Tools;
|
|||
|
|
|||
|
namespace DispenserUI.Views.Controls;
|
|||
|
|
|||
|
public partial class Table : UserControl
|
|||
|
{
|
|||
|
public static readonly StyledProperty<IEnumerable> ItemsProperty =
|
|||
|
AvaloniaProperty.Register<Table, IEnumerable>(nameof(Items));
|
|||
|
|
|||
|
public static readonly StyledProperty<int> TotalProperty =
|
|||
|
AvaloniaProperty.Register<Table, int>(nameof(Total));
|
|||
|
|
|||
|
public static readonly StyledProperty<int> PageSizeProperty =
|
|||
|
AvaloniaProperty.Register<Table, int>(nameof(PageSize));
|
|||
|
|
|||
|
public static readonly StyledProperty<int> CurrentPageProperty =
|
|||
|
AvaloniaProperty.Register<Table, int>(nameof(CurrentPage));
|
|||
|
|
|||
|
public static readonly StyledProperty<int> PagesProperty =
|
|||
|
AvaloniaProperty.Register<Table, int>(nameof(Pages));
|
|||
|
|
|||
|
public static readonly StyledProperty<bool> ShowIndexProperty =
|
|||
|
AvaloniaProperty.Register<Table, bool>(nameof(ShowIndex), true);
|
|||
|
|
|||
|
public static readonly StyledProperty<int> MaxDisplayPagesProperty =
|
|||
|
AvaloniaProperty.Register<Table, int>(nameof(MaxDisplayPages), 10);
|
|||
|
|
|||
|
|
|||
|
public event EventHandler<int> NextPage;
|
|||
|
|
|||
|
public event EventHandler<int> PreviousPage;
|
|||
|
|
|||
|
public event EventHandler<int> PageChanged;
|
|||
|
|
|||
|
public Table()
|
|||
|
{
|
|||
|
InitializeComponent();
|
|||
|
TableContent = this.FindControl<DataGrid>("TableContent");
|
|||
|
PrePageBtn = this.FindControl<Button>("PrePageBtn");
|
|||
|
NextPageBtn = this.FindControl<Button>("NextPageBtn");
|
|||
|
PageRepeater = this.FindControl<StackPanel>("PageRepeater");
|
|||
|
this.GetObservable(ItemsProperty).Subscribe(its =>
|
|||
|
{
|
|||
|
Items = its;
|
|||
|
Dispatcher.UIThread.InvokeAsync(RenderTable);
|
|||
|
});
|
|||
|
PrePageBtn!.Click += OnPreviousPage;
|
|||
|
NextPageBtn!.Click += OnNextPage;
|
|||
|
}
|
|||
|
|
|||
|
private void InitializeComponent()
|
|||
|
{
|
|||
|
AvaloniaXamlLoader.Load(this);
|
|||
|
}
|
|||
|
|
|||
|
public IEnumerable Items
|
|||
|
{
|
|||
|
get => GetValue(ItemsProperty);
|
|||
|
set => SetValue(ItemsProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
public int Total
|
|||
|
{
|
|||
|
get => GetValue(TotalProperty);
|
|||
|
set => SetValue(TotalProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
public int PageSize
|
|||
|
{
|
|||
|
get => GetValue(PageSizeProperty);
|
|||
|
set => SetValue(PageSizeProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
public bool ShowIndex
|
|||
|
{
|
|||
|
get => GetValue(ShowIndexProperty);
|
|||
|
set => SetValue(ShowIndexProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
public int CurrentPage
|
|||
|
{
|
|||
|
get => GetValue(CurrentPageProperty);
|
|||
|
set => SetValue(CurrentPageProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
public int Pages
|
|||
|
{
|
|||
|
get => GetValue(PagesProperty);
|
|||
|
set => SetValue(PagesProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
public int MaxDisplayPages
|
|||
|
{
|
|||
|
get => GetValue(MaxDisplayPagesProperty);
|
|||
|
set => SetValue(MaxDisplayPagesProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 上一页
|
|||
|
/// </summary>
|
|||
|
/// <param name="sender"></param>
|
|||
|
/// <param name="e"></param>
|
|||
|
private void OnPreviousPage(object? sender, RoutedEventArgs e)
|
|||
|
{
|
|||
|
if (CurrentPage == 1)
|
|||
|
{
|
|||
|
ToastUtil.Info("无上一页数据");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
PreviousPage?.Invoke(this, CurrentPage - 1);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 下一页
|
|||
|
/// </summary>
|
|||
|
/// <param name="sender"></param>
|
|||
|
/// <param name="e"></param>
|
|||
|
private void OnNextPage(object? sender, RoutedEventArgs e)
|
|||
|
{
|
|||
|
if (CurrentPage == Pages)
|
|||
|
{
|
|||
|
ToastUtil.Info("无下一页数据");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
NextPage?.Invoke(this, CurrentPage + 1);
|
|||
|
}
|
|||
|
|
|||
|
private void RenderTable()
|
|||
|
{
|
|||
|
TableContent.ItemsSource = new List<object>();
|
|||
|
TableContent.Columns.Clear();
|
|||
|
|
|||
|
if (Items.IsNullOrEmpty()) return;
|
|||
|
|
|||
|
|
|||
|
if (ShowIndex)
|
|||
|
{
|
|||
|
var index = new DataGridTextColumn
|
|||
|
{
|
|||
|
Header = "序号",
|
|||
|
Width = new DataGridLength(80),
|
|||
|
Binding = new Binding
|
|||
|
{
|
|||
|
RelativeSource = new RelativeSource
|
|||
|
{
|
|||
|
Mode = RelativeSourceMode.FindAncestor,
|
|||
|
AncestorType = typeof(DataGridRow),
|
|||
|
},
|
|||
|
Path = "Header"
|
|||
|
},
|
|||
|
};
|
|||
|
TableContent.Columns.Add(index);
|
|||
|
|
|||
|
TableContent.LoadingRow += LoadingRow;
|
|||
|
}
|
|||
|
|
|||
|
TableContent.ItemsSource = Items;
|
|||
|
|
|||
|
List<DataGridTextColumn> columns = [];
|
|||
|
foreach (var item in Items)
|
|||
|
{
|
|||
|
var type = item.GetType();
|
|||
|
var properties =
|
|||
|
type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
|||
|
foreach (var property in properties)
|
|||
|
{
|
|||
|
var description = property.GetCustomAttribute<DescriptionAttribute>();
|
|||
|
var hide = property.GetCustomAttribute<Hide>();
|
|||
|
|
|||
|
if (hide != null) continue;
|
|||
|
|
|||
|
var column = new DataGridTextColumn
|
|||
|
{
|
|||
|
Header = description!.Description,
|
|||
|
Binding = new Binding(property.Name),
|
|||
|
Width = new DataGridLength(1, DataGridLengthUnitType.Star)
|
|||
|
};
|
|||
|
columns.Add(column);
|
|||
|
}
|
|||
|
|
|||
|
TableContent.Columns.AddRange(columns);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// 计算显示的起始页和结束页
|
|||
|
int startPage = Math.Max(1, CurrentPage - MaxDisplayPages / 2);
|
|||
|
int endPage = Math.Min(Pages, startPage + MaxDisplayPages - 1);
|
|||
|
|
|||
|
// 如果起始页被推前了(例如,当前页靠近总页数末尾)
|
|||
|
if (endPage - startPage + 1 < MaxDisplayPages)
|
|||
|
{
|
|||
|
startPage = Math.Max(1, endPage - MaxDisplayPages + 1);
|
|||
|
}
|
|||
|
|
|||
|
// 渲染导航栏,最多只显示10页
|
|||
|
List<Button> pageButtons = [];
|
|||
|
for (var i = startPage; i <= endPage; i++)
|
|||
|
{
|
|||
|
var page = i;
|
|||
|
var btn = new Button
|
|||
|
{
|
|||
|
Content = i,
|
|||
|
Width = 30,
|
|||
|
Height = 30,
|
|||
|
Foreground = Brushes.Black,
|
|||
|
FontSize = 12,
|
|||
|
Background = Brushes.Transparent,
|
|||
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|||
|
VerticalContentAlignment = VerticalAlignment.Center,
|
|||
|
Margin = new Thickness(5, 0, 5, 0)
|
|||
|
};
|
|||
|
if (i == CurrentPage)
|
|||
|
{
|
|||
|
btn.Foreground = Brushes.DodgerBlue;
|
|||
|
btn.FontWeight = FontWeight.Bold;
|
|||
|
}
|
|||
|
|
|||
|
btn.Click += (sender, args) =>
|
|||
|
{
|
|||
|
CurrentPage = page;
|
|||
|
PageChanged?.Invoke(this, page);
|
|||
|
};
|
|||
|
|
|||
|
pageButtons.Add(btn);
|
|||
|
}
|
|||
|
|
|||
|
PageRepeater.Children.Clear();
|
|||
|
PageRepeater.Children.AddRange(pageButtons);
|
|||
|
}
|
|||
|
|
|||
|
private void LoadingRow(object? sender, DataGridRowEventArgs e)
|
|||
|
{
|
|||
|
e.Row.Header = e.Row.GetIndex() + 1;
|
|||
|
}
|
|||
|
}
|