仿新浪微博实现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

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

posted @ 2012-09-04 13:59  海之澜  阅读(4660)  评论(5编辑  收藏  举报