Avalonia 自定义分页控件

public class Pagination : ContentControl
{
	private int _currentPage = 1;
	private Button _prevPageButton = null!;
	private Button _nextPageButton = null!;
	private Button goToPageButton = null!;
	private TextBox _pageNumberTextBox = null!;
	private TextBlock _pageInfoTextBlock = null!;
	private ComboBox _itemsPerPageComboBox = null!;

	// 定义可绑定的 ItemsSource 属性
	public static readonly StyledProperty<IEnumerable> ItemsSourceProperty =
    	AvaloniaProperty.Register<Pagination, IEnumerable>(nameof(ItemsSource), defaultBindingMode: BindingMode.TwoWay);

	public IEnumerable ItemsSource
	{
    	get => GetValue(ItemsSourceProperty);
    	set => SetValue(ItemsSourceProperty, value);
	}

	// 定义可绑定的 ItemsPerPage 属性
	public static readonly StyledProperty<int> ItemsPerPageProperty =
    AvaloniaProperty.Register<Pagination, int>(nameof(ItemsPerPage), 10, defaultBindingMode: BindingMode.TwoWay);

	public int ItemsPerPage
	{
    	get => GetValue(ItemsPerPageProperty);
    	set => SetValue(ItemsPerPageProperty, value);
	}

	// 定义可绑定的 TotalItems 属性
	public static readonly StyledProperty<int> TotalItemsProperty =
    AvaloniaProperty.Register<Pagination, int>(nameof(TotalItems), defaultValue: -1);

	public int TotalItems
	{
    	get => GetValue(TotalItemsProperty);
    	set => SetValue(TotalItemsProperty, value);
	}

	// 定义可绑定的 IsBackendPaging 属性
	public static readonly StyledProperty<bool> IsBackendPagingProperty =
    AvaloniaProperty.Register<Pagination, bool>(nameof(IsBackendPaging), false, defaultBindingMode: BindingMode.TwoWay);

	public bool IsBackendPaging
	{
    	get => GetValue(IsBackendPagingProperty);
    	set => SetValue(IsBackendPagingProperty, value);
	}

	// 定义事件,通知外部逻辑当前页数和每页条数,后台分页模式下返回当前页号和每页条数
	public event Action<Pagination, int, int, IEnumerable> PageChanged = null!;

	public Pagination()
	{
    	InitializeControls();
	}
	/// <summary>
	/// 重写 OnApplyTemplate 方法
	/// </summary>
	/// <param name="e"></param>
	protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
	{
    	base.OnApplyTemplate(e); // 传递 TemplateAppliedEventArgs 参数

    	// Replace the following line:  
    	var index = _itemsPerPageComboBox.ItemsSource?
            .Cast<int>() // 将 IEnumerable 转换为 IEnumerable<int>
            .Select((value, idx) => new { Value = value, Index = idx }) // 将值和索引绑定
            .FirstOrDefault(x => x.Value == ItemsPerPage)?.Index; // 查找目标值并返回索引
    	_itemsPerPageComboBox.SelectedIndex = index == null ? 0 : (int)index;
    	// 确保控件初始化完成后再添加监听
    	if (!IsBackendPaging)
    	{
        	// 伪分页,监听数据源属性变化
        	ItemsSourceProperty.Changed.AddClassHandler<Pagination>((x, e) => x.UpdatePagination());
    	}
    	else
    	{
        	// 后台分页,监听总数属性变化,更新分页信息
        	TotalItemsProperty.Changed.AddClassHandler<Pagination>((x, e) => x.UpdatePaginationInfo());
    	}

    	// 监听每页条数属性变化
    	ItemsPerPageProperty.Changed.AddClassHandler<Pagination>((x, e) => x.UpdatePagination());


    	_prevPageButton.Click += (s, e) => GoToPage(_currentPage - 1);
    	_nextPageButton.Click += (s, e) => GoToPage(_currentPage + 1);


    	goToPageButton.Click += (s, e) =>
    	{
        	if (int.TryParse(_pageNumberTextBox.Text, out int pageNumber))
        	{
            	int totalPages = CalculateTotalPages();
            	if (pageNumber < 1 || pageNumber > totalPages)
            	{
                	_pageNumberTextBox.Text = string.Empty; // 清空输入框
                	return;
            	}
            	GoToPage(pageNumber);
        	}
    	};

    	_itemsPerPageComboBox.SelectionChanged += (s, e) =>
    	{
        	if (_itemsPerPageComboBox.SelectedItem is int selectedItemsPerPage)
        	{
            	ItemsPerPage = selectedItemsPerPage;
            	_currentPage = 1; // 重置到第一页
            	UpdatePagination();
        	}
    	};

    	// 初始化分页
    	UpdatePagination();
	}

	// 初始化控件
	private void InitializeControls()
	{
    	// 创建分页控件
    	var paginationPanel = new StackPanel
    	{
        	Orientation = Orientation.Horizontal,
        	HorizontalAlignment = HorizontalAlignment.Right,
        	Margin = new Thickness(0, 10, 0, 0)
    	};

    	_itemsPerPageComboBox = new ComboBox
    	{
        	Width = 100,
        	Margin = new Thickness(0, 0, 10, 0),
        	ItemsSource = new[] { 10, 20, 50, 100, 500, 1000 }
    	};

    	// 上一页按钮
    	_prevPageButton = new Button
    	{
        	Content = "上一页",
        	Padding = new Thickness(5, 0),
        	FontSize = 14,
        	Height = 34,
        	Margin = new Thickness(0, 0, 5, 0)
    	};

    	// 下一页按钮
    	_nextPageButton = new Button
    	{
        	Content = "下一页",
        	Padding = new Thickness(5, 0),
        	FontSize = 14,
        	Height = 34,
        	Margin = new Thickness(5, 0, 0, 0)
    	};

    	// 页号输入框
    	_pageNumberTextBox = new TextBox
    	{
        	Width = 100,
        	Margin = new Thickness(5, 0, 5, 0),
        	FontSize = 14,
        	Height = 34,
        	VerticalAlignment = VerticalAlignment.Center
    	};

    	// 页号跳转按钮
    	goToPageButton = new Button
    	{
        	Content = "跳转",
        	Padding = new Thickness(5,0),
        	FontSize = 14,
        	Height = 34,
        	Margin = new Thickness(5, 0, 0, 0)
    	};


    	// 当前页/总页数显示
    	_pageInfoTextBlock = new TextBlock
    	{
        	VerticalAlignment = VerticalAlignment.Center,
        	Margin = new Thickness(10, 0, 10, 0)
    	};

    	paginationPanel.Children.Add(_itemsPerPageComboBox);
    	paginationPanel.Children.Add(_prevPageButton);
    	paginationPanel.Children.Add(_pageInfoTextBlock);
    	paginationPanel.Children.Add(_pageNumberTextBox);
    	paginationPanel.Children.Add(goToPageButton);
    	paginationPanel.Children.Add(_nextPageButton);

    	// 将分页控件设置为 Content
    	this.Content = paginationPanel;
	}
	//后台分页,由于只提供数据总数,所以只触发更新,不触发事件
	private void UpdatePaginationInfo()
	{
    	if (TotalItems<0) return;
    	_pageInfoTextBlock.Text = $"第 {_currentPage} 页 / 共 {TotalItems} 页";
    	_prevPageButton.IsEnabled = _currentPage > 1;
    	_nextPageButton.IsEnabled = _currentPage < TotalItems;
	}
	// 更新分页并触发Change
	private void UpdatePagination()
	{
    	if (ItemsSource == null) return;
    	if (!IsBackendPaging&&ItemsSource.Cast<object>().Count() == 0) return;
    	int totalPages = CalculateTotalPages();
    	_pageInfoTextBlock.Text = $"第 {_currentPage} 页 / 共 {totalPages} 页";
    	_prevPageButton.IsEnabled = _currentPage > 1;
    	_nextPageButton.IsEnabled = _currentPage < totalPages;

    	if (!IsBackendPaging)
    	{
        	// 伪分页模式:返回当前页的数据集
        	var pagedData = ItemsSource.Cast<object>()
            .Skip((_currentPage - 1) * ItemsPerPage)
            .Take(ItemsPerPage);
        	PageChanged?.Invoke(this,_currentPage, ItemsPerPage,pagedData);
    	}
    	else
    	{
        	// 后台分页模式:返回当前页号和每页条数
        	PageChanged?.Invoke(this,_currentPage, ItemsPerPage, Enumerable.Empty<object>());
    	}
	}

	// 计算总页数
	private int CalculateTotalPages()
	{
    	int totalItems = TotalItems == -1 ? ItemsSource.Cast<object>().Count() : TotalItems;
    	return (int)Math.Ceiling((double)totalItems / ItemsPerPage);
	}

	// 跳转到指定页
	private void GoToPage(int page)
	{
    	_currentPage = page;
    	UpdatePagination();
	}
}
posted @ 2025-04-13 10:53  一步一个坑  阅读(221)  评论(0)    收藏  举报