博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何用两种方式同时实现ListBox的滚动功能
阅读量:5968 次
发布时间:2019-06-19

本文共 3534 字,大约阅读时间需要 11 分钟。

今天,要用WPF实现一个可以通过Windows触屏左右滑动的ListBox控件,并且,同时也可以通过点击两个按钮,进行左右滑动。

实现这个控件,有几个难点:

  1. 两种方式,都需要有一个共同的值或方式来记录滑动的距离和方向。否则通过一种方式滑动以后,再用另外一种方式,就会出现错误的距离滑动。

  2. 滑动的距离不容易获取,因为ListBox没有类似于OffSet的属性。

  3. 当ListBox的内容的元素比较多的时候,也就是可以滑动的时候,不容易得知那些元素是露在外面的。

Xaml的相关代码:

有种方法,可以实现第二种方式滚动:

navItemsListBox.ScrollIntoView(navItemsListBox.Items[++CurrentRightIndex]);

这种方法,可以让ListBox滚动到其包含的某个元素。但是因为不能记录滚动的具体位置,所以对第一种划屏的方式无能为力,所以这种方法不能采用。

有种方法,可以完美实现。

首先通过VisualTree的方法获得内嵌在ListBox中的ScrollViewer:

Decorator border = VisualTreeHelper.GetChild(navItemsListBox, 0) as Decorator;        if (border != null)        {            scrollViewer = border.Child as ScrollViewer;            if (scrollViewer != null)            {                scrollViewer.ScrollToHorizontalOffset(theOffset);            }        }

因为ScrollViewer是可以记录滚动的偏差的,比如HorizontalOffset属性就是记录水平的滚动偏差的。获取了内嵌在ListBox中的ScrollViewer,也就间接的获取了ListBox的滚动偏差。

然后,获取navItemsListBox中的ListBoxItem,用来计算每个元素的宽度和ListBox左右能滑动的最大宽度:

ListBoxItem theItem = (ListBoxItem)(navItemsListBox.ItemContainerGenerator.ContainerFromIndex(0));var itemWidth = theItem.ActualWidth;var itemsTotalWidth = (navItemsListBox.Items.Count - MAXSHOWNINDEX) * itemWidth;

其中,MAXSHOWNINDEX是ListBox能同时展现在外面的最多元素的个数。

那么这个方法的原理就是:因为无论是通过触屏滑屏还是点击按钮滚动,都会改变ListBox中ScrollViewer的HorizontalOffset的值(当然,也会触发ListBox的ScrollViewer.ScrollChanged事件,我就是通过这个事件来了解这个方法的),那么每次在点击按钮进行滚动的时候,首先要获取当前的HorizontalOffset的值,然后再用

scrollViewer.ScrollToHorizontalOffset(theOffset);

这个方法再次改变HorizontalOffset。这样,就通过HorizontalOffset这个值来统一管理两种滚动方法的偏移量了。

当然,以上功能可以直接采用ScrollViewer实现,但是由于历史代码遗留的原因,不得不采用ListBox。

最终的code-behind代码如下:

private const int MAXSHOWNINDEX = 9;    private ScrollViewer scrollViewer = new ScrollViewer();    private double theOffset = 0;    private void UserControl_Loaded(object sender, RoutedEventArgs e)    {        Decorator border = VisualTreeHelper.GetChild(navItemsListBox, 0) as Decorator;        if (border != null)        {                        scrollViewer = border.Child as ScrollViewer;            if (scrollViewer != null)            {                scrollViewer.ScrollToHorizontalOffset(theOffset);            }        }    }    private void CategoryToRight(object sender, RoutedEventArgs e)    {        ListBoxItem theItem = (ListBoxItem)(navItemsListBox.ItemContainerGenerator.ContainerFromIndex(0));        var itemWidth = theItem.ActualWidth;        var itemsTotalWidth = (navItemsListBox.Items.Count - MAXSHOWNINDEX) * itemWidth;        theOffset = scrollViewer.HorizontalOffset;        if (theOffset + itemWidth > itemsTotalWidth)        {            theOffset = itemsTotalWidth;        }        else            theOffset += itemWidth;                scrollViewer.ScrollToHorizontalOffset(theOffset);    }    private void CategoryToLeft(object sender, RoutedEventArgs e)    {        ListBoxItem theItem = (ListBoxItem)(navItemsListBox.ItemContainerGenerator.ContainerFromIndex(0));        var itemWidth = theItem.ActualWidth;        theOffset = scrollViewer.HorizontalOffset;        if (theOffset - itemWidth < 0)        {            theOffset = 0;        }        else            theOffset -= itemWidth;        scrollViewer.ScrollToHorizontalOffset(theOffset);    }

转载地址:http://yxqax.baihongyu.com/

你可能感兴趣的文章
shell脚本:一键安装LAMP、LNMP脚本
查看>>
CloudStack 的配置、部署与管理,以及 API 的使用
查看>>
心理成熟的十五条标准(转)
查看>>
Oracle-查看锁
查看>>
深度学习帮助人工智能走得更远
查看>>
Python从菜鸟到高手(5):数字
查看>>
使用DPM 2012 Sp1保护SQL server 2012 Sp1
查看>>
基于开源技术的上网行为管理实现方案
查看>>
Hadoop运维记录系列(十)
查看>>
Python学习笔记四(Python OS模块)
查看>>
走过13,展望14----希望是个好东西
查看>>
SQL Server 2012 AlwaysOn高可用配置之八:新建可用性组
查看>>
★核心关注点_《信息系统项目管理师考试考点分析与真题详解》
查看>>
卢松松:如何复制暴利产品
查看>>
Google Glass是工具不是玩具
查看>>
如何寻找高质量流量日入三百+
查看>>
f_bfree和f_bavail的区别
查看>>
Tegra3 vSMP架构Android运行时CPU热插拔及高低功耗CPU切换
查看>>
风雨飘摇中的HP会分拆Arcsight业务吗?
查看>>
技术者的好奇心和惯性
查看>>