1. 程式人生 > >wpf listbox 滾動翻頁功能

wpf listbox 滾動翻頁功能

最近有個需求,需要通過 listbox滾動實現翻頁功能。查了下資料 總結如下。

方案一:利用ScrollViewer.ScrollChanged事件來實現當偏移量到底部時,進行相應操作。

xaml中

  <ListBox BorderBrush="Red" Grid.Column="0" ItemsSource="{Binding SchoolNoticeList}" ItemTemplate="{StaticResource listboxitemT}" ScrollViewer.ScrollChanged="ListBox_ScrollChanged"/>
       

對應的事件
  private void ListBox_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            ScrollViewer sv = e.OriginalSource as ScrollViewer;
            ListScrollWndViewModel vm = this.DataContext as ListScrollWndViewModel;
            if (sv != null)
            {
                Console.WriteLine(e.VerticalOffset.ToString());
                if(IsVerticalScrollBarAtButtom(sv))
                {             
                    vm.MsgTest = "已到底部";
                }
                else{
                    vm.MsgTest="未到底部";
                
                }
            }
        }

        public bool IsVerticalScrollBarAtButtom(ScrollViewer s)
        {

            bool isAtButtom = false;
            double dVer = s.VerticalOffset;
            double dViewport = s.ViewportHeight;
            double dExtent = s.ExtentHeight;
            Console.WriteLine("dVer:"+dVer+" dViewport:"+dViewport+" dExtent:"+dExtent);
            if (dVer != 0)
            {
                if (dVer + dViewport == dExtent)
                {
                    isAtButtom = true;
                }
                else
                {
                    isAtButtom = false;
                }
            }
            else
            {
                isAtButtom = false;
            }
            if (s.VerticalScrollBarVisibility == ScrollBarVisibility.Disabled
                || s.VerticalScrollBarVisibility == ScrollBarVisibility.Hidden)
            {
                isAtButtom = true;
            }
            return isAtButtom;
        }
按照微軟(https://msdn.microsoft.com/zh-cn/library/ms612678)的解釋 
VerticalOffset是獲取包含滾動內容的垂直偏移量的值。,viewportheight是獲取包含內容視區垂直大小的值。ExtentHeight 獲取包含盤區垂直大小的一個值。

利用圖來解釋一下


這是一個20個數據長度(從0到20)長度的listbox,可以看出VerticalOffset其實就是從上往下覆蓋的元素數量(4),viewportheight是控制元件可供人看到的元素數量(10=13-4+1) ExtentHeight是總的元素數量(20)。通過改變視窗大小,viewportheight會跟隨改變,拖動滾動條,VerticalOffset也會跟著改變。判斷滾動到底部的條件 自然就是

VerticalOffset+viewportheight==ExtentHeight

但這種方式 有兩個問題

一個是如何向前翻頁,如果簡單的以VerticalOffset==0 來判斷,當初始化的時候,就會發現scorllchanged就會觸發,並且VerticalOffset等於0

二是當最後一頁資料較少,滾動條不出現時,scorllchanged就永遠不會被觸發,也就是說最後一頁無法向前翻。

方案二:

直接利用previewmousewheel來判斷向前向後翻轉。

xaml

            <ListBox BorderBrush="Green" Grid.Column="1" ItemsSource="{Binding SchoolNoticeList}" ItemTemplate="{StaticResource listboxitemT}" PreviewMouseWheel="ListBox_PreviewMouseWheel" />

對應的響應事件
  private void ListBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            ListScrollWndViewModel vm = this.DataContext as ListScrollWndViewModel;
            Console.WriteLine(e.Delta);
            if (e.Delta > 0)
            {
                Console.WriteLine("正在向上滾動滑輪");
                vm.MsgTest = "正在向上滾動滑輪";
            }
            else
            {
                Console.WriteLine("正在向下滾動滑輪");
                vm.MsgTest = "正在向下滾動滑輪";
            }
        }

這種方法的劣勢在於頁面上資料不能太多(不能出現滾動條),否則被覆蓋的資料不會顯現出來。

把兩種結合起來,也許會更好,利用previewmousewheel來觸發事件,當滾動條偏移量為0,則向上翻頁,滾動條到底部則 向下翻頁。

首先需要獲得listbox中的scrollviewer

   Decorator border = VisualTreeHelper.GetChild(listbox3, 0) as Decorator;
            if (border != null)
            {
                scrollViewer = border.Child as ScrollViewer;               
            }
然後在previewmousewheel裡面進行事件處理
  private void ListBox3_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            ListScrollWndViewModel vm = this.DataContext as ListScrollWndViewModel;
            Console.WriteLine(e.Delta);
            if (e.Delta > 0)
            {
                if (scrollViewer.VerticalOffset == 0)
                {
                    Pre();                }
            }
            else
            {
                if (scrollViewer.VerticalOffset + scrollViewer.ViewportHeight == scrollViewer.ExtentHeight)
                {
                    Next();
                    scrollViewer.ScrollToTop();
                }
            }
        }