很多时候会有到底加载更多的需求,而ScrollViewer不支持继承,无法继承它进行扩展,只能通过触发器来控制到底的事件(当然,可以通过UserControl去扩展)

  思路:定义一个Trigger,自定义依赖属性,绑定到该属性到ScrollViewer的VerticalOffset属性上,然后监听属性的变化,就能监控到滚动事件了,然后判断滚动的位置从而判断出是否到底

  原理很简单,下面看实现

// *************************************************
//
// 作者:bomo
// 小组:WP开发组
// 创建日期:2014/7/9 0:10:32
// 版本号:V1.00
// 说明:
//
// *************************************************
//
// 修改历史:
// Date WhoChanges Made
// 2014/7/9 0:10:32 bomo Initial creation
//
// ************************************************* using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media; namespace XTuOne.Common.Helpers
{
/// <summary>
/// 扩展依赖属性类
/// </summary>
public static class DependencyObjectExtend
{
public static IEnumerable<DependencyObject> GetDescendant(this DependencyObject element)
{
var list = new List<DependencyObject>();
var count = VisualTreeHelper.GetChildrenCount(element);
for (int i = ; i < count; i++)
{
var child = VisualTreeHelper.GetChild(element, i);
list.Add(child);
list.AddRange(child.GetDescendant());
} return list;
} /// <summary>
/// 查找子孙节点中符合类型的首个节点
/// </summary>
public static T GetFirstDescendantOfType<T>(this DependencyObject start) where T : DependencyObject
{
return start.GetDescendantsOfType<T>().FirstOrDefault();
} /// <summary>
/// 查找子孙节点中符合类型的节点
/// </summary>
public static IEnumerable<T> GetDescendantsOfType<T>(this DependencyObject start) where T : DependencyObject
{
return start.GetDescendants().OfType<T>();
} /// <summary>
/// 获取所有的子孙阶段
/// </summary>
public static IEnumerable<DependencyObject> GetDescendants(this DependencyObject start)
{
if (start == null)
yield break; var queue = new Queue<DependencyObject>();
queue.Enqueue(start);
yield return start; while (queue.Count > )
{
var parent = queue.Dequeue();
var count2 = VisualTreeHelper.GetChildrenCount(parent); for (int i = ; i < count2; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
yield return child;
queue.Enqueue(child);
}
}
}
}
}

依赖属性扩展类

// *************************************************
//
// 作者:bomo
// 小组:WP开发组
// 创建日期:2014/7/11 11:45:14
// 版本号:V1.00
// 说明:
//
// *************************************************
//
// 修改历史:
// Date WhoChanges Made
// 2014/7/11 11:45:14 bomo Initial creation
//
// ************************************************* using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interactivity;
using XTuOne.Common.Helpers; namespace XTuOne.Utility.Helpers
{
/// <summary>
/// ScrollViewer到底触发器
/// </summary>
public class ScrollViewerToBottomTrigger : TriggerBase<DependencyObject>
{
public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.Register(
"VerticalOffset", typeof(double), typeof(ScrollViewerToBottomTrigger),
new PropertyMetadata(0.0, VerticalOffsetPropertyChanged)); private ScrollViewer scrollView; public double VerticalOffset
{
get { return (double)GetValue(VerticalOffsetProperty); }
set { SetValue(VerticalOffsetProperty, value); }
} public static void VerticalOffsetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = d as ScrollViewerToBottomTrigger;
if (behavior != null)
behavior.OnVerticalOffsetChanged();
} protected override void OnAttached()
{
base.OnAttached(); if (AssociatedObject is FrameworkElement)
{
(AssociatedObject as FrameworkElement).SizeChanged += control_SizeChanged;
}
} private void control_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (!(AssociatedObject is FrameworkElement))
return; var scroll = AssociatedObject.GetFirstDescendantOfType<ScrollViewer>();
if (scroll != null)
{
AttachedScroll(scroll);
(AssociatedObject as FrameworkElement).SizeChanged -= control_SizeChanged;
}
} private void AttachedScroll(ScrollViewer scroll)
{
if (scroll == null)
return;
scrollView = scroll; var binding = new Binding { Source = scroll, Path = new PropertyPath("VerticalOffset") };
BindingOperations.SetBinding(this, VerticalOffsetProperty, binding);
} private void OnVerticalOffsetChanged()
{
var scroll = scrollView;
if (scroll == null)
return; if (scroll.ExtentHeight - scroll.VerticalOffset - scroll.ViewportHeight <= )
{
InvokeActions(null);
}
}
}
}

通过Trigger实现,由于Trigger是一个附加元素,可以附加到任何一个符合的元素上(子孙元素包含ScrollViewer的控件),同时触发的事件可以支持绑定

使用(使用CM进行绑定)

<ScrollViewer x:Name="ScrollViewer">
<i:Interaction.Triggers>
<utilityHelpers:ScrollViewerToBottomTrigger>
<micro:ActionMessage MethodName="LoadMessage"/>
</utilityHelpers:ScrollViewerToBottomTrigger>
</i:Interaction.Triggers>
</ScrollViewer>

一个触发器只能对应触发一个事件(用于绑定),如果需要多个扩展,比如:到顶触发,滑动触发等,就需要编写多个触发器,如果这样可以考虑在UserControl扩展

发现一个问题(上面触发器在ListBox失效):

  ListBox中的ScrollViewer的ExtentHeight是数据项的个数,比如ListBox有20条数据,那么ExtentHeight就是20

  ListBox中的VerticalOffset是表示当前位置,如果当前屏幕中显示的第一条是第12条数据,那么VerticalOffset就是12.xxx

  ListBox中的ViewportHeight是根据第一屏的数据计算的,把List滑动到顶部,然后计算出页面内有几个项,这个值是假定List内所有的项的大小都是一样的,如果ListBox中的ItemTemplate的高度不是相同大小的,就会出现误差,导致下面三种情况都可能出现

    ExtentHeight == VerticalOffset + ViewportHeight

    ExtentHeight > VerticalOffset + ViewportHeight

    ExtentHeight < VerticalOffset + ViewportHeight

如果要用在ListBox上的话,需要保证每一项的高度都相同,否则会有误差(有时提前触发,有时候不触发)

【WP8】ScrollViewer滑动到底触发器(ListBox失效)的更多相关文章

  1. pyqt5在textBrowser添加文本并自动滑动到底

    pyqt5在textBrowser添加文本并自动滑动到底 说明: 1.按下按钮pushButton,把单行文本框lineEdit里的内容循环不断的添加到多行文本展示框textBrowser.2.必须要 ...

  2. Unity触发器有时失效的原因

    unity里面的触发器有时候不起作用,我原以为是失效了.其实是这样的,所谓触发器就是被触发的物体,例如你子弹打小怪.如果把子弹设置成触发器那么是不成功的,因为子弹是主动的啊,那么把小怪设置成触发器了呢 ...

  3. 移动端ios上下滑动翻页事件失效

    移动端开发过程中,在添加上下滑动事件时候,引入了最常用的移动端库zepto.js及其touch模块,有一种现象,安卓的手机没有问题,上下滑动翻页很正常 :但是到了ios上面,好啊,上下滑动会出现弹性滚 ...

  4. selenium+python关于页面滚动条滑动到底的问题总结

    1.如果滚动条是针对整个HTML可以用如下方式: js = "var q=document.documentElement.scrollTop=10000" # documentE ...

  5. WPF ItemsControl 控件支持鼠标滚轮滑动

    此文章意在解决在WPF中ItemsControl类型的集合控件支持鼠标滚轮操作,并可控制滚动的速度. 第一步:给ItemsControl添加滚轮事件. this.listBox.AddHandler( ...

  6. 【朝花夕拾】Android自定义View篇之(七)Android事件分发机制(下)滑动冲突解决方案总结

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/11072989.html],谢谢! 前面两篇文章,花了很大篇幅讲解了Android的事件分发机制 ...

  7. 写一个js向左滑动删除 交互特效的插件——Html5 touchmove

    需求描述 需要实现类似QQ中对联系人的操作:向左滑动,滑出删除按钮.滑动超过一半时松开则自动滑到底,不到一半时松开则返回原处. 纯js实现 使用了h5的touchmove等事件,以及用js动态改变cs ...

  8. [WPF系列]-ListBox

    引言 本文就WPF中的ListBox常用项给以实例代码演示,包括隐蔽属性的设置,Style设置,以及ControlTemplate的自定义.   Listbox平滑滚动 <ListBox Ite ...

  9. WPF的ScrollViewer鼠标的滚动

    在C# 中,两个ScrollViewer嵌套在一起或者ScrollViewer里面嵌套一个ListBox.Listview(控件本身有scrollviewer)的时候,我们本想要的效果是鼠标滚动整个S ...

随机推荐

  1. 使用 WebSphere ILOG JRules 开发保险应用系统

    使用 WebSphere ILOG JRules 开发保险应用系统 概述 保险行业在国内是一个充分竞争的行业,竞争的加剧导致保险公司的业务管理等各项费用在增长.而保险公司业务支撑系统的先进性与灵活支撑 ...

  2. android开发——从相冊中选择图片不裁剪

    转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46864777 问题: 在郭神的第一行代码中,第8章的从相冊中选择图片这块,从相冊选 ...

  3. C语言 · 算年龄

    算年龄 英国数学家德摩根出生于19世纪初叶(即18xx年). 他年少时便很有才华.一次有人问他的年龄,他回答说: “到了x的平方那年,我刚好是x岁”. 请你计算一下,德摩根到底出生在哪一年. 题中的年 ...

  4. MyEclipse10中配置开发Python所需要的PyDev 绝对靠谱 不忽悠!

    在NLP(自然语言处理)这个领域中,Python具有良好的声誉,于是也想学习一下.首先第一步就是需要在计算机上配置Python环境.由于Python自带的编辑器太简单,使用起来不顺手,于是就考虑在相对 ...

  5. Postgres数据库补丁脚本示例

    SET client_encoding = 'UTF8';-- 新建序列和表DROP TABLE IF EXISTS cms_user_unit;DROP SEQUENCE IF EXISTS cms ...

  6. Jackson学习笔记(三)<转>

    概述 使用jackson annotations简化和增强的json解析与生成. Jackson-2.x通用annotations列表:https://github.com/FasterXML/jac ...

  7. java中反向转义org.apache.commons.lang3.StringEscapeUtils.unescapeJava

    工具类中包含类反向转义的方法: eorderHistory.setSubPrintTemplates(StringEscapeUtils.unescapeJava(eorderHistory.getS ...

  8. linux服务器的性能分析与优化(十三)

    [教程主题]:1.linux服务器的性能分析与优化 [主要内容] [1]影响Linux服务器性能的因素 操作系统级 Ø CPU 目前大部分CPU在同一时间只能运行一个线程,超线程的处理器可以在同一时间 ...

  9. Linux高频命令精讲(三)

    [教程主题]:2.Linux高频命令精讲 [2.1]Linux的运行方式 图形运行方式 - 本地使用KDE/Gnome集成环境 - 运行X Server远程使用图形环境 命令行(字符运行)方式 - 本 ...

  10. hbase源码系列(十一)Put、Delete在服务端是如何处理?

    在讲完之后HFile和HLog之后,今天我想分享是Put在Region Server经历些了什么?相信前面看了<HTable探秘>的朋友都会有印象,没看过的建议回去先看看,Put是通过Mu ...