• 仿新浪微博实现ListBox下拉刷新和到底部自动加载


    一、下拉刷新
    下拉刷新实现思路:
    1、定义一个PullDownToRefreshPanel容器控件。为它添加3种状态模板,分别是PullingDownTemplate,ReadyToReleaseTemplate
         和RefreshingTemplate,顾名思义分别是显示下拉状态模板,显示松开刷新状态模板和正在刷新中的状态模板。
    2、定义自己的ListBox让它继承系统的ListBox,并重写它的Style,把ScrollViewer的ManipulationMode属性设为Conrtrol(必需),
         只有这样才能和我们的定义的PullDownToRefreshPanel兼容。ManipulationMode属性系统默认是System;区别就是,System的
         滑动效果更好。这里的ListBox的Style定义可以参考安装的SDK目录里面的系统定义,路径大致是:c->Program Files(x86)->
         Microsoft SDKs->Windows Phone->v7.1->Design->System.Windows.xaml.

    View Code

    3、编写PullDownToRefreshPanel控件,主要是把PullDownToRefreshPanel和ScrollViewer联系起来,通过PullDwonReflesh距离滚动条的位置
         来实现下拉刷新功能. 具体的实现,代码里有很好的注释。相信难不到你

    View Code

    4、实现自定义ListBox->CustListBox,代码很简单直接上。

    View Code
     1 [TemplatePart(Name = CustListBox.ScrollViewerPart, Type = typeof(ScrollViewer))]
     2 
     3 public class CustListBox : ListBox
     4 
     5 {
     6 
     7 public const string ScrollViewerPart = "ScrollViewer";
     8 
     9 
    10 
    11 public CustListBox()
    12 
    13 {
    14 
    15 this.DefaultStyleKey = typeof(CustListBox);
    16 
    17 }
    18 
    19 
    20 
    21 #region AutoScrollMargin DependencyProperty
    22 
    23 
    24 
    25 public static readonly DependencyProperty AutoScrollMarginProperty = DependencyProperty.Register(
    26 
    27 "AutoScrollMargin", typeof(int), typeof(CustListBox), new PropertyMetadata(32));
    28 
    29 
    30 
    31 public double AutoScrollMargin
    32 
    33 {
    34 
    35 get
    36 
    37 {
    38 
    39 return (int)this.GetValue(CustListBox.AutoScrollMarginProperty);
    40 
    41 }
    42 
    43 set
    44 
    45 {
    46 
    47 this.SetValue(CustListBox.AutoScrollMarginProperty, value);
    48 
    49 }
    50 
    51 }
    52 
    53 
    54 
    55 #endregion
    56 
    57 }

    5、使用要求   
         包含PullDwonReflesh的容器,必须直接或间接的包含滚动条。
         例如:一个StackPanel包含一个PullDownToRefreshPanel 和一个ListBox,而ListBox内部包含一个ScrollViewer来实现子项的显示。
    6、为了使用起来更方便,我把CustListBox和PullDownToRefreshPanel 又封装了一层
         xaml

    View Code
     1 <UserControl x:Class="PullDwonReflesh.Themes.CustListbox"
     2 
     3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     4 
     5 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     6 
     7 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     8 
     9 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    10 
    11 mc:Ignorable="d"
    12 
    13 FontFamily="{StaticResource PhoneFontFamilyNormal}"
    14 
    15 FontSize="{StaticResource PhoneFontSizeNormal}"
    16 
    17 Foreground="{StaticResource PhoneForegroundBrush}"
    18 
    19 d:DesignHeight="480" d:DesignWidth="480" xmlns:my="clr-namespace:PullDwonReflesh"
    20 
    21 
    22 
    23 xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
    24 
    25 x:Name="this">
    26 
    27 
    28 
    29 <Grid x:Name="LayoutRoot">
    30 
    31 <Grid.RowDefinitions>
    32 
    33 <RowDefinition Height="Auto" />
    34 
    35 <RowDefinition Height="*" />
    36 
    37 </Grid.RowDefinitions>
    38 
    39 <my:PullDownToRefreshPanel x:Name="refreshPanel" RefreshRequested="refreshPanel_RefreshRequested" Grid.Row="0" />
    40 
    41 <my:CustListBox x:Name="custListBox" Grid.Row="1" Margin="12,0,12,12" toolkit:TiltEffect.IsTiltEnabled="True"
    42 
    43 ItemsSource="{Binding ElementName=this, Path=ItemsSource}" 
    44 
    45 ItemTemplate="{Binding ElementName=this,Path=ItemTemplate}"
    46 
    47 SelectionChanged="CustListBox_SelectionChanged" >
    48 
    49 <!--<ListBox.ItemsPanel>
    50 
    51 <ItemsPanelTemplate>
    52 
    53 <toolkit:WrapPanel/>
    54 
    55 </ItemsPanelTemplate>
    56 
    57 </ListBox.ItemsPanel>
    58 
    59 <ListBox.ItemContainerStyle>
    60 
    61 <Style TargetType="ListBoxItem">
    62 
    63 <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    64 
    65 </Style>
    66 
    67 </ListBox.ItemContainerStyle>-->
    68 
    69 </my:CustListBox>
    70 
    71 </Grid>
    72 
    73 </UserControl>
    View Code
      1 using System;
      2 
      3 using System.Collections.Generic;
      4 
      5 using System.Linq;
      6 
      7 using System.Net;
      8 
      9 using System.Windows;
     10 
     11 using System.Windows.Controls;
     12 
     13 using System.Windows.Documents;
     14 
     15 using System.Windows.Input;
     16 
     17 using System.Windows.Media;
     18 
     19 using System.Windows.Media.Animation;
     20 
     21 using System.Windows.Shapes;
     22 
     23 using System.Collections;
     24 
     25 
     26 
     27 namespace PullDwonReflesh.Themes
     28 
     29 {
     30 
     31 public partial class CustListbox : UserControl
     32 
     33 {
     34 
     35 public event SelectionChangedEventHandler SelectionChanged;
     36 
     37 public event EventHandler RefreshRequested;
     38 
     39 
     40 
     41 public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(CustListbox), new PropertyMetadata(""));
     42 
     43 public IEnumerable ItemsSource
     44 
     45 {
     46 
     47 get
     48 
     49 {
     50 
     51 return (IEnumerable)base.GetValue(ItemsSourceProperty);
     52 
     53 }
     54 
     55 set
     56 
     57 {
     58 
     59 base.SetValue(ItemsSourceProperty, value);
     60 
     61 }
     62 
     63 }
     64 
     65 
     66 
     67 private DataTemplate _ItemTemplate = null;
     68 
     69 public DataTemplate ItemTemplate
     70 
     71 {
     72 
     73 get
     74 
     75 {
     76 
     77 return _ItemTemplate;
     78 
     79 }
     80 
     81 set
     82 
     83 {
     84 
     85 _ItemTemplate = value;
     86 
     87 custListBox.ItemTemplate = value;
     88 
     89 }
     90 
     91 }
     92 
     93 
     94 
     95 public static readonly DependencyProperty IsRefreshingProperty = DependencyProperty.Register("IsRefreshing", typeof(bool), typeof(CustListbox), new PropertyMetadata(false, (d, e) => ((CustListbox)d).OnIsRefreshingChanged(e)));
     96 
     97 public bool IsRefreshing
     98 
     99 {
    100 
    101 get
    102 
    103 {
    104 
    105 return (bool)this.GetValue(CustListbox.IsRefreshingProperty);
    106 
    107 }
    108 
    109 set
    110 
    111 {
    112 
    113 this.SetValue(CustListbox.IsRefreshingProperty, value);
    114 
    115 }
    116 
    117 }
    118 
    119 
    120 
    121 protected void OnIsRefreshingChanged(DependencyPropertyChangedEventArgs e)
    122 
    123 {
    124 
    125 this.refreshPanel.IsRefreshing = (bool)e.NewValue;
    126 
    127 }
    128 
    129 
    130 
    131 public CustListbox()
    132 
    133 {
    134 
    135 InitializeComponent();
    136 
    137 }
    138 
    139 
    140 
    141 private void CustListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    142 
    143 {
    144 
    145 if (SelectionChanged != null)
    146 
    147 {
    148 
    149 SelectionChanged(sender, e);
    150 
    151 }
    152 
    153 }
    154 
    155 
    156 
    157 private void refreshPanel_RefreshRequested(object sender, EventArgs e)
    158 
    159 {
    160 
    161 if (RefreshRequested != null)
    162 
    163 {
    164 
    165 RefreshRequested(sender, e);
    166 
    167 }
    168 
    169 }
    170 
    171 }
    172 
    173 }

    到此,下拉刷新已经完成,可以拿出来单独使用。


    二、ListBox滚动到底部自动加载
    这个实现起来就更简单,思路
    1、检测ListBox中的ScrollViewer控件状态
    2、若状态不为滚动中:根据ScrollViewer的ExtentHeight与VerticalOffset,判断是否到底,并执行请求加载数据。

    首先获取ScrollViewer,这个上面实现下拉的中已经得到了,这里在App定义一个变量把下拉时获得的ScrollViewer保存起来,并在这里作为目标滚动条。
    然后编写获得状态函数,如下

    View Code
     1 private VisualStateGroup FindVisualState(FrameworkElement element, string name)
     2 
     3 {
     4 
     5 if (element == null)
     6 
     7 return null;
     8 
     9 
    10 
    11 IList groups = VisualStateManager.GetVisualStateGroups(element);
    12 
    13 foreach (VisualStateGroup group in groups)
    14 
    15 {
    16 
    17 if (group.Name == name)
    18 
    19 return group;
    20 
    21 }
    22 
    23 
    24 
    25 return null;
    26 
    27 }

    接下来根据状态的改变做相应的加载功能,代码如下

    复制代码
     1 void visualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
     2 
     3 {
     4 
     5 var visualState = e.NewState.Name;
     6 
     7 if (visualState == "NotScrolling")
     8 
     9 {
    10 
    11 var v1 = _ScrollViewer.ExtentHeight - _ScrollViewer.VerticalOffset;
    12 
    13 var v2 = _ScrollViewer.ViewportHeight * 1.5;
    14 
    15 
    16 
    17 if (v1 <= v2 && !custListBox.IsRefreshing)
    18 
    19 {
    20 
    21 AddString(index, 20);
    22 
    23 visualState += "_End";
    24 
    25 }
    26 
    27 }
    28 
    29 }
    复制代码

    最后,在页面的loaded里把这些代码串联起来就OK了。如下:

    复制代码
     1 private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
     2 
     3 {
     4 
     5 if (_IsHookedScrollEvent)
     6 
     7 return;
     8 
     9 _ScrollViewer = App._ScrollViewer;
    10 
    11 if (_ScrollViewer != null)
    12 
    13 {
    14 
    15 _IsHookedScrollEvent = true;
    16 
    17 FrameworkElement element = VisualTreeHelper.GetChild(_ScrollViewer, 0) as FrameworkElement;
    18 
    19 if (element != null)
    20 
    21 {
    22 
    23 VisualStateGroup visualStateGroup = FindVisualState(element, "ScrollStates");
    24 
    25 visualStateGroup.CurrentStateChanged += new EventHandler<VisualStateChangedEventArgs>(visualStateGroup_CurrentStateChanged);
    26 
    27 }
    28 
    29 }
    30 
    31 }
    复制代码

    本文参考:http://www.hugwp.com/thread-2058-1.html
    和Jason Ginchereau的博客

    源码:https://files.cnblogs.com/qq278360339/PullDwonReflesh(%E4%B8%8B%E6%8B%89%E5%88%B7%E6%96%B0%EF%BC%8C%E5%88%B0%E5%BA%95%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD).zip

    本文版权归作者和卤面网所有,
    转载请标明原始出处

  • 相关阅读:
    three.js 显示中文字体 和 tween应用
    Caddy v1 版本增加插件
    Git 常用命令大全
    批量部署ssh免密登陆
    Python MySQLdb 模块使用方法
    python XlsxWriter创建Excel 表格
    DB2数据库的日志文件管理
    Linux 文本对比 diff 命令详解(整理)
    ssh 免交互登录 ,远程执行命令脚本。
    linux 出错 “INFO: task xxxxxx: 634 blocked for more than 120 seconds.”的3种解决方案(转)
  • 原文地址:https://www.cnblogs.com/wuzhsh/p/2670307.html
Copyright © 2020-2023  润新知