using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.LogicalTree; using Avalonia.Markup.Xaml; using ReactiveUI.Avalonia; using ReactiveUI; using System.Reactive.Disposables; using AuroraDesk.Presentation.ViewModels.Pages; using System; using System.Linq; using System.Threading; using System.Threading.Tasks; using Avalonia.Threading; using Avalonia.VisualTree; namespace AuroraDesk.Presentation.Views.Pages; /// /// 图片浏览页面视图 /// /// 核心功能: /// - 实现滚动检测,当滚动接近底部时自动加载更多图片 /// - 距底部小于500px时触发加载 /// - 防止重复加载的保护逻辑 /// public partial class ImageGalleryPageView : ReactiveUserControl { private ScrollViewer? _scrollViewer; private CancellationTokenSource? _scrollDetectionCancellationToken; private CancellationTokenSource? _layoutCheckCancellationToken; private bool _isLoadingMore = false; // 防止重复加载 public ImageGalleryPageView() { InitializeComponent(); this.WhenActivated(disposables => { // 当视图激活时,设置滚动检测 Dispatcher.UIThread.Post(() => SetupScrollDetection(), DispatcherPriority.Loaded); // 当视图停用时,清理资源 disposables.Add(Disposable.Create(() => { _scrollDetectionCancellationToken?.Cancel(); _scrollDetectionCancellationToken?.Dispose(); _layoutCheckCancellationToken?.Cancel(); _layoutCheckCancellationToken?.Dispose(); })); }); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } /// /// 设置滚动检测 /// 监听 ScrollViewer 的滚动事件,当接近底部时加载更多 /// private void SetupScrollDetection() { // 查找 ScrollViewer _scrollViewer = this.FindControl("MainScrollViewer"); if (_scrollViewer == null) { _scrollViewer = this.GetLogicalDescendants().OfType().FirstOrDefault(); } if (_scrollViewer != null) { // 绑定滚动事件 _scrollViewer.ScrollChanged += OnScrollChanged; // 监听布局完成事件,确保在布局完成后检查是否需要加载更多 _scrollViewer.LayoutUpdated += OnLayoutUpdated; // 延迟检查一次,确保在初始加载完成后能自动加载更多 _ = Task.Run(async () => { await Task.Delay(800); await Dispatcher.UIThread.InvokeAsync(async () => { if (!_isLoadingMore && ViewModel != null) { await CheckAndLoadMoreAsync(); } }, DispatcherPriority.Background); }); } } /// /// 布局更新时检查是否需要加载更多 /// private void OnLayoutUpdated(object? sender, EventArgs e) { // 只在布局稳定后检查一次,避免频繁触发 if (!_isLoadingMore && ViewModel != null && _scrollViewer != null) { // 防抖:取消之前的布局检查任务 _layoutCheckCancellationToken?.Cancel(); _layoutCheckCancellationToken?.Dispose(); _layoutCheckCancellationToken = new CancellationTokenSource(); var token = _layoutCheckCancellationToken.Token; // 检查是否需要加载更多(延迟检查,避免在布局过程中频繁触发) _ = Task.Run(async () => { await Task.Delay(200, token); if (token.IsCancellationRequested) return; await Dispatcher.UIThread.InvokeAsync(async () => { if (!token.IsCancellationRequested && !_isLoadingMore && ViewModel != null) { await CheckAndLoadMoreAsync(); } }, DispatcherPriority.Background); }, token); } } /// /// 滚动时检查是否需要加载更多 /// private void OnScrollChanged(object? sender, ScrollChangedEventArgs e) { // 防抖:取消之前的检测任务 _scrollDetectionCancellationToken?.Cancel(); _scrollDetectionCancellationToken?.Dispose(); _scrollDetectionCancellationToken = new CancellationTokenSource(); var token = _scrollDetectionCancellationToken.Token; // 延迟200ms检测,避免频繁触发 _ = Task.Delay(200, token).ContinueWith(async _ => { if (!token.IsCancellationRequested && ViewModel != null && _scrollViewer != null) { await CheckAndLoadMoreAsync(); } }, token); } /// /// 检查是否需要加载更多图片 /// 当滚动位置距底部小于500px时,触发加载 /// private async Task CheckAndLoadMoreAsync() { if (ViewModel == null || _scrollViewer == null || _isLoadingMore) return; try { // 如果正在加载初始数据,不触发加载更多 if (ViewModel.IsLoading) return; // 获取滚动信息 var scrollOffset = _scrollViewer.Offset.Y; var viewportHeight = _scrollViewer.Viewport.Height; var extentHeight = _scrollViewer.Extent.Height; if (extentHeight <= 0 || viewportHeight <= 0) return; // 计算距离底部的距离 var maxScrollOffset = extentHeight - viewportHeight; var distanceToBottom = maxScrollOffset - scrollOffset; // 如果距离底部小于500px,且还有更多内容未加载,则触发加载 if (distanceToBottom < 500 && ViewModel.Images.Count < ViewModel.TotalImageCount) { _isLoadingMore = true; try { // 调用 ViewModel 加载更多 await ViewModel.LoadMoreImagesAsync(); } finally { // 延迟重置标志,避免短时间内重复触发 await Task.Delay(300); _isLoadingMore = false; } } } catch (Exception ex) { // 忽略错误,避免影响UI System.Diagnostics.Debug.WriteLine($"检查加载更多时出错: {ex.Message}"); _isLoadingMore = false; } } }