WPF中實現動態加載圖片瀏覽器(邊滾動邊加載)
在做圖片瀏覽器程序時,遇到圖片數量巨大的情況(如幾百張、上千張),一次性加載所有圖片會導致界面卡頓甚至程序崩潰。
本文介紹一種 WPF + Prism 實現動態分頁加載圖片的方法,結合 ScrollViewer
滾動條觸底檢測,實現 “邊滾動,邊加載” 的流暢體驗。
1. 界面設計:4×4 顯示 + 滾動條
我們希望界面每次顯示 4×4,共 16 張圖片,每張圖片帶有邊框。
XAML示例
<ScrollViewer VerticalScrollBarVisibility="Auto" ScrollChanged="ScrollViewer_ScrollChanged"><ItemsControl ItemsSource="{Binding Images}"><ItemsControl.ItemsPanel><ItemsPanelTemplate><UniformGrid Columns="4"/></ItemsPanelTemplate></ItemsControl.ItemsPanel><ItemsControl.ItemTemplate><DataTemplate><Border BorderBrush="Gray" BorderThickness="1" Margin="5"><Image Source="{Binding}" Stretch="Uniform"/></Border></DataTemplate></ItemsControl.ItemTemplate></ItemsControl>
</ScrollViewer>
ScrollViewer
包裹ItemsControl
,開啟垂直滾動。- 使用
UniformGrid
布局,4列均勻分布。 - 每張圖片用
Border
包一層,美觀且清晰分隔。
2. 后臺邏輯:ViewModel 分頁加載
ViewModel 負責管理圖片列表和分頁邏輯。
public class ImageBrowserViewModel : BindableBase
{private const int PageSize = 16;private readonly List<string> allImagePaths = new();public ObservableCollection<BitmapImage> Images { get; } = new();private int currentPage = 0;public bool IsLoading { get; private set; }public void LoadAllImagePaths(string folderPath){allImagePaths.Clear();var extensions = new[] { ".jpg", ".png", ".bmp" };var files = Directory.GetFiles(folderPath).Where(f => extensions.Contains(Path.GetExtension(f).ToLower())).ToList();allImagePaths.AddRange(files);currentPage = 0;Images.Clear();}public async Task LoadNextPageAsync(){if (IsLoading) return;IsLoading = true;var nextImages = allImagePaths.Skip(currentPage * PageSize).Take(PageSize).ToList();foreach (var path in nextImages){await Task.Run(() =>{var bitmap = new BitmapImage();bitmap.BeginInit();bitmap.CacheOption = BitmapCacheOption.OnLoad;bitmap.UriSource = new Uri(path);bitmap.EndInit();bitmap.Freeze();App.Current.Dispatcher.Invoke(() => Images.Add(bitmap));});}currentPage++;IsLoading = false;}
}
LoadAllImagePaths
:一次性記錄所有圖片路徑,但不立刻加載圖片內容。LoadNextPageAsync
:每次按頁加載圖片,使用Task.Run
+Dispatcher.Invoke
,避免界面卡頓。
3. 滾動到底時加載新圖片
在 ScrollViewer
的 ScrollChanged
事件中,檢測是否接近底部,如果是則請求 ViewModel 加載下一頁:
private async void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{var scrollViewer = (ScrollViewer)sender;if (scrollViewer.VerticalOffset + scrollViewer.ViewportHeight >= scrollViewer.ExtentHeight - 50) // 接近底部50像素{if (DataContext is ImageBrowserViewModel vm && !vm.IsLoading){await vm.LoadNextPageAsync();}}
}
ExtentHeight
是總高度,ViewportHeight
是當前可視區域高度,VerticalOffset
是當前滾動位置。
當滾動接近底部 50px 內,就觸發加載。
4. 總結
通過以上方法,我們實現了:
- 初始只加載少量圖片,快速打開界面。
- 用戶滾動時,按需分頁加載后續圖片。
- 界面不卡頓,體驗絲滑流暢。
這種設計特別適合處理大量圖片瀏覽、視頻幀查看、縮略圖管理器等場景。