You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI 3中如何绑定ItemsRepeater当前页面索引至TextBox?

实现WinUI 3中ScrollViewer滚动时显示当前页面索引的功能

要实现滚动时在TextBox中显示当前页面索引,你可以通过以下步骤完成:


1. 完善ViewModel的PageIndex属性

确保你的ViewModel实现INotifyPropertyChanged接口,并且PageIndex属性能正确触发属性变更通知,这样绑定的TextBox才能实时更新:

public class YourViewModel : INotifyPropertyChanged
{
    private int _pageIndex = 1;
    public int PageIndex
    {
        get => _pageIndex;
        set
        {
            if (_pageIndex != value)
            {
                _pageIndex = value;
                OnPropertyChanged();
            }
        }
    }

    public ObservableCollection<PdfImage> Pages { get; } = new();

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 实现ScrollViewer滚动时的索引计算逻辑

在ScrollViewer_ViewChanged事件处理器中,计算当前视口中可见面积最大的页面,并更新ViewModel的PageIndex:

private void ScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
    if (sender is not ScrollViewer scrollViewer || 
        PdfImageRepeater.ItemsSource == null || 
        ViewModel.Pages.Count == 0)
        return;

    var zoomFactor = scrollViewer.ZoomFactor;
    if (zoomFactor == 0) return;

    var viewportTop = scrollViewer.VerticalOffset;
    var viewportBottom = viewportTop + scrollViewer.ViewportHeight;
    var realizedElements = PdfImageRepeater.GetRealizedElements();

    int bestIndex = -1;
    double maxOverlap = 0;

    foreach (var element in realizedElements)
    {
        // 获取元素在ScrollViewer中的物理像素位置
        var transform = element.TransformToVisual(scrollViewer);
        var elementTopPhysical = transform.TransformPoint(new Point(0, 0)).Y;
        var elementBottomPhysical = elementTopPhysical + element.ActualHeight;

        // 转换为ScrollViewer内容的逻辑坐标系(与VerticalOffset一致)
        var elementTop = elementTopPhysical / zoomFactor;
        var elementBottom = elementBottomPhysical / zoomFactor;

        // 计算元素与视口的重叠高度
        var overlapTop = Math.Max(viewportTop, elementTop);
        var overlapBottom = Math.Min(viewportBottom, elementBottom);
        var overlapHeight = overlapBottom - overlapTop;

        if (overlapHeight > 0 && PdfImageRepeater.TryGetElementIndex(element, out int index))
        {
            // 选择重叠面积最大的页面,若面积相同则选择上方的页面
            if (overlapHeight > maxOverlap || 
                (overlapHeight == maxOverlap && index < bestIndex))
            {
                maxOverlap = overlapHeight;
                bestIndex = index;
            }
        }
    }

    // 更新ViewModel的索引(转为1-based)
    if (bestIndex != -1 && ViewModel.PageIndex != bestIndex + 1)
    {
        ViewModel.PageIndex = bestIndex + 1;
    }
}

3. 优化TextBox的导航体验

处理Enter键跳转

在TextBox的KeyDown事件中添加Enter键处理,让用户无需失去焦点即可跳转页面:

XAML中添加事件绑定:

<TextBox Text="{x:Bind ViewModel.PageIndex, Mode=TwoWay}" 
         LostFocus="PageIndexTextBox_LostFocus" 
         x:Name="PageIndexTextBox" 
         InputScope="Number"
         KeyDown="PageIndexTextBox_KeyDown"/>

代码实现:

private void PageIndexTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == Windows.System.VirtualKey.Enter)
    {
        PageIndexTextBox_LostFocus(sender, e);
        PageIndexTextBox.Focus(FocusState.Programmatic); // 保持焦点
    }
}

修复无效输入的重置逻辑

修改LostFocus事件处理器,当输入无效时自动重置为当前页面索引:

private void PageIndexTextBox_LostFocus(object sender, RoutedEventArgs e)
{
    if (int.TryParse(PageIndexTextBox.Text, out int pageIndex))
    {
        var zeroBasedIndex = pageIndex - 1;
        if (zeroBasedIndex >= 0 && zeroBasedIndex < ViewModel.Pages.Count)
        {
            var pageItem = PdfImageRepeater.GetOrCreateElement(zeroBasedIndex);
            pageItem.UpdateLayout();
            pageItem.StartBringIntoView();
            ViewModel.PageIndex = pageIndex; // 确保ViewModel同步正确值
        }
        else
        {
            // 索引超出范围,重置为当前页面
            ScrollViewer_ViewChanged(scroll, null);
        }
    }
    else
    {
        // 输入非数字,重置为当前页面
        ScrollViewer_ViewChanged(scroll, null);
    }
}

4. 初始化页面索引

在页面加载时触发一次索引计算,确保初始显示正确的页面编号:

XAML中添加页面Loaded事件:

<Page ... Loaded="Page_Loaded">

代码实现:

private void Page_Loaded(object sender, RoutedEventArgs e)
{
    ScrollViewer_ViewChanged(scroll, null);
}

内容的提问来源于stack exchange,提问作者אפרת

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 21:35:52