最近有个需求,需要通过 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();
}
}
}