【WP8】ScrollViewer滑动到底触发器

很多时候会有到底加载更多的需求,而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 = 0; 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 > 0)
            {
                var parent = queue.Dequeue();
                var count2 = VisualTreeHelper.GetChildrenCount(parent);

                for (int i = 0; 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 <= 5)
            {
                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扩展

【WP8】ScrollViewer滑动到底触发器

时间: 2024-08-09 18:16:47

【WP8】ScrollViewer滑动到底触发器的相关文章

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

pyqt5在textBrowser添加文本并自动滑动到底 说明: 1.按下按钮pushButton,把单行文本框lineEdit里的内容循环不断的添加到多行文本展示框textBrowser.2.必须要用线程做这件事,不然主程序会卡死.3.必须添加sleep(),不然主程序会卡死.4.用函数的闭包做这样的事情,效果很好. 信号与槽的连接: 1 self.pushButton_2.clicked.connect(MainWindow.slot1) 槽函数: 1 def slot1(self): 2

ScrollViewer滚动到底来触发加载数据的Behavior

最近项目中遇到加载数据的性能问题, 原因是.net4.0的虚拟化支持不够完成,有好多bug在4.5才修复. 我们只能利用大家通用的做法来延迟加载数据: 每次加载固定少量的数据,当拖动到底后,继续加载后续相同数量的数据. 思路: 监听ScrollViewer的VerticalOffsetProperty,如果值达到允许滚动的高度ScrollableHeight,则发出event通知外部处理加载逻辑. 使用方法: 1.对于ItemsControl编辑控件模板,在其中的ScrollViewer中加入b

PullToRefreshScrollView实现顶层搜索框 滑动可隐藏 下面刷自定义GridView

最近项目里有个需求,要求用GridView去显示商品,滑动到底部下拉能加载更多商品,向下滑动过程中需要隐藏掉自定义的Action(搜索框)布局,向上滑动能显示出来,整体效果类似淘宝APP搜索结果页那样. 起初觉得挺简单的,但是后来才发现还是得转一点脑子.最开始我想用PullToRefreshGridView,但是后来发现GridView没有添加headview的方法,只能采用PullToRefreshScrollView内嵌套GridView的方法,Scrollview里多放一个空白布局当Gri

PullToRefreshScrollView+GridView,实现向下滑动中隐藏自定义Action布局

最近电商类项目有个需求挺头疼,要求用GridView去显示商品,滑动到底部下拉能加载更多商品,向下滑动过程中需要隐藏掉自定义的Action布局,向上滑动能显示出来,整体效果类似淘宝APP搜索结果页那样. 起初觉得挺简单的,但是后来才发现还是得转一点脑子.最开始我想用PullToRefreshGridView,但是后来发现GridView没有添加headview的方法,只能采用PullToRefreshScrollView内嵌套GridView的方法,Scrollview里多放一个空白布局当Gri

监测uitableview 向上滑动和向下滑动的事件

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat height = _varietyTableView.frame.size.height; CGFloat distanceFromButton = _varietyTableView.contentSize.height - _varietyTableView.contentOffset.y; if (distanceFromButton == height) {

Android: ScrollView监听滑动到顶端和底端

在项目中需要监听ScrollView滑动到顶端和底端的时候以实现自己的ScrollView,那么怎样去监听呢?今天查看了一下ScrollView的源码,找到了一种方法.先看一下源码中的overScrollBy()方法: 1 protected boolean overScrollBy(int deltaX, int deltaY, 2 int scrollX, int scrollY, 3 int scrollRangeX, int scrollRangeY, 4 int maxOverScro

UWP开发入门(七)——下拉刷新

本篇意在给这几天Win10 Mobile负面新闻不断的某软洗地,想要证明实现一个简单的下拉刷新并不困难.UWP开发更大的困难在于懒惰,缺乏学习的意愿.而不是“某软连下拉刷新控件都没有”这样的想法. 之前我也没有进行过下拉刷新的研究.于是先去google了几篇blog学习了一下,然后再看了某软官方的Sample.(同学们啊官方有下拉刷新的Sample啊!就在Git上啊!不要钱无门槛啊!)学习之后发现实现的方式大体分为两类. 一类是以某软Sample和博客园MS-UAP封装的PullToRefres

Swift 为你的webView定制标题

有些情况下,应用中会使用webView来加载大段的文字,而且还是带各种标签的. 不能全部过滤掉,那样的话,内容就会失去原本想表达的格式. 可是,如果webView中并没有将内容的标题或其他杂项包含进那一大段内容,而是单独的存放在字典的另一个字段中,而且此时是不带任何标签的纯文本. 而且最终的页面又需要同时显示这些内容,这样的境地就比较尴尬了. 接下来这种方案可以缓解这种尴尬: 首先介绍一下实现思路:scrollView加在self.view上沾满屏幕,scrollView的顶部留出一段空白用于放

手机淘宝 521 性能优化项目揭秘

又是一年双十一,亿万用户都会在这一天打开手机淘宝,高兴地在会场页面不断浏览,面对琳琅满目的商品图片,抢着添加购物车,下单付款.为了让用户更顺畅更方便地实现这一切,做到“如丝般顺滑”,双十一前夕手机淘宝成立了“521”(我爱你)性能优化项目,在日常优化基础之上进行三个方面的专项优化攻关,分别是1)H5页面的一秒法则:2)启动时间和页面帧率提升20%:3)Android内存占用降低50%.优化过程中遇到的困难,思考后找寻的方案,实施后提取的经验都会在下面详细地介绍给读者. 第一章 一秒法则的实现 “