背景
由於我們的數據展示中使用過的listBox,如果一下子展示過多的數據時,如果還需要加載圖片等,可能會導致加載過程中等待時間過長,用戶體驗不不佳,因此我們采用分頁的方式來實現更佳的用戶體驗,但是需要實現當滑動滾動條(這里是向底部滑動過程中)進行數據加載,也就是相當於點擊下一頁的效果。
實現思路
ListBox本身有一個ScrollView,ScrollView有幾個屬性可以標記是否當前已經滑到底部,然后進行數據的追加。
使用VisualTreeHelper來獲取ListBox中的ScrollViewer
獲取方式: scrollViewer = FindSimpleVisualChild<ScrollViewer>(listBox);
T FindSimpleVisualChild<T>(DependencyObject element) where T : class { while (element != null) { if (element is T) return element as T; element = VisualTreeHelper.GetChild(element, 0); } return null; }
然后監聽: scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;當滑動到底部時去加載數據。
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) { if (isBootomScrollView(scrollViewer)) { if (pageSize < Total) { page++; pageSize = page * 10; // NextPaged?.Invoke( page,10);
//追加數據的邏輯 } } } private bool isBootomScrollView(ScrollViewer view) { bool isBottom = false; double dVer = view.VerticalOffset; double vViewport = view.ViewportHeight; double eextent = view.ExtentHeight; if (dVer != 0) { if (dVer + vViewport == eextent) { isBottom = true; } else { isBottom = false; } } else { isBottom = false; } return isBottom; }
每次首頁加載時需要注意,一定要將Scrollviewer設置滑動到頂部,否則數據會一直加載
完整代碼如下:public event Action<object> SelectItemChanged;
private int Total = 0; int pageSize = 0; int page = 1; ScrollViewer scrollViewer = null; /// <summary> /// 刷新數據 /// </summary> /// <param name="total"></param> /// <param name="newlist"></param> public void ReFleshImage(int total, ObservableCollection<Data> newlist) { Task.Run(() => { Total = total; if (newlist==null) { pageSize = OldData.Count; } this.Dispatcher.InvokeAsync(() => { if (alreadyHookedScrollEvents) return; if (scrollViewer == null)//首次加載中去獲取ScrollView可能會報異常,因此在這里再次判斷獲取 { scrollViewer = FindSimpleVisualChild<ScrollViewer>(listBox); if (scrollViewer != null) { scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged; scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged; alreadyHookedScrollEvents = true; } } else { scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged; scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged; alreadyHookedScrollEvents = true; } alreadyHookedScrollEvents = true;//標注下次不需要再獲取 }); }); Task.Run(() => { this.Dispatcher.InvokeAsync(() => { try { List<BitmapSource> list = new List<BitmapSource>(); if (newlist == null) { foreach (var item in OldData) { var img = ImageService.GetImageByUrl(item.imagePath); list.Add(img); } for (int i = 0; i < list.Count; i++) { OldeData[i].ImageSource = list[i]; } } else { foreach (var item in newlist) { var img = ImageService.GetImagebyUrl(item.imagePath); list.Add(img); } for (int i = 0; i < list.Count; i++) { newlist[i].ImageSource = list[i]; } List<Data> oldlist = OldData.ToList(); oldlist.AddRange(newlist); OlData = oldlist.ToObservableCollection(); } } catch (Exception ex) { } }); }); } /// <summary> /// 再次加載 /// </summary> public void ResetPage() { try { page = 1; if (scrollViewer != null) { scrollViewer.ScrollToHome(); } } catch (Exception ex) { CommonLib.LogClass.SystemErrLog("", ex.ToString()); } } public event Action<int,int> NextPaged; bool alreadyHookedScrollEvents = false; void UserControl_Loaded(object sender, RoutedEventArgs e) { Task.Run(() => { this.Dispatcher.InvokeAsync(() => { try { scrollViewer = FindSimpleVisualChild<ScrollViewer>(listBox); } catch (Exception ex) { } }); }); } T FindSimpleVisualChild<T>(DependencyObject element) where T : class { while (element != null) { if (element is T) return element as T; element = VisualTreeHelper.GetChild(element, 0); } return null; } private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) { if (isBootomScrollView(scrollViewer)) { if (pageSize < Total) { page++; pageSize = page * 10; NextPaged?.Invoke( page,10);
} } } private bool isBootomScrollView(ScrollViewer view) { bool isBottom = false; double dVer = view.VerticalOffset; double vViewport = view.ViewportHeight; double eextent = view.ExtentHeight; if (dVer != 0) { if (dVer + vViewport == eextent) { isBottom = true; } else { isBottom = false; } } else { isBottom = false; } return isBottom; } }
以上只是個人見解,應該有更好的方式。希望大家指點一下。