LongListSelector是一个加强版的列表控件,它可以实现分组的列表,如系统人脉列表的交互效果就可以利用LongListSelector控件去实现,同时LongListSelector也一样可以实现和ListBox一样的列表效果。在使用LongListSelector控件的时候可以使用IsGroupingEnabled属性来控制你要实现的是分组的效果,还是非分组的列表效果。
下面我们用LongListSelector来实现一个非分组的列表效果,同时还要实现的功能是列表下拉自动刷新的效果。LongListSelector实现非分组列表效果和ListBox控件是类似的,通过对ItemTemplate模板进行设置,然后绑定集合的相关属性就可以了。在前面的章节由介绍过一个使用ListBox控件判断列表滚动到底的例子,实现的原理是通过可视化树获取ListBox的ScrollViewer控件,然后根据ScrollViewer控件的垂直位移属性来判断ListBox控件什么时候滚动到底。但是LongListSelector内部没有采用ScrollViewer控件,所以我们不能采用这种方式来实现下拉自动刷新的功能。那么我们这个例子是通过LongListSelector控件的ItemRealized事件去控制自动刷新的逻辑,因为LongListSelector控件是对数据进行虚拟化处理的,当列表向下滚动的时候下面的数据就会不断地被实例化,当数据实例化的时候就会触发ItemRealized事件,所以我只需要监控到当列表最后一个数据实例化的时候就可以出发数据刷新的逻辑就可以了。代码如下所示:
<phone:LongListSelector x:Name="lls" ItemsSource="{Binding Items}" IsGroupingEnabled="False"> <phone:LongListSelector.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding FirstName}" FontSize="30"></TextBlock> <TextBlock Text="{Binding LastName}" FontSize="30" Margin="30,0,0,0"></TextBlock> </StackPanel> </DataTemplate> </phone:LongListSelector.ItemTemplate> </phone:LongListSelector>
public partial class MainPage : PhoneApplicationPage { // 绑定的数据集合 public ObservableCollection<Item> Items { get; set; } // 数据加载的标识 public bool IsLoading = false; // 线程锁的对象 private object o = new object(); // 构造函数 public MainPage() { InitializeComponent(); // 列表初始化加载100个数据项 Items = new ObservableCollection<Item>(); for (int i = 0; i < 100; i++) { Items.Add(new Item { FirstName = "Li" + i, LastName = "Lei" + i }); } this.DataContext = this; } // 页面加载完成,订阅列表的ItemRealized事件 private void PhoneApplicationPage_Loaded_1(object sender, RoutedEventArgs e) { lls.ItemRealized += lls_ItemRealized; } // ItemRealized事件处理程序,在这里判断刷新的时机 void lls_ItemRealized(object sender, ItemRealizationEventArgs e) { // 因为该事件会被多个线程进入,所以添加线程锁,控制下面的代码只能单个线程去执行 lock (o) { if (!IsLoading) { if (e.ItemKind == LongListSelectorItemKind.Item) { if ((e.Container.Content as Item).Equals(lls.ItemsSource[lls.ItemsSource.Count - 1])) { // 设置IsLoading为true,在加载数据的过程中,禁止多次进入 IsLoading = true; // 显示系统托盘的进度条 Microsoft.Phone.Shell.ProgressIndicator progressIndicator = new Microsoft.Phone.Shell.ProgressIndicator(); Microsoft.Phone.Shell.SystemTray.ProgressIndicator = progressIndicator; progressIndicator.Text = "加载中..."; progressIndicator.IsIndeterminate = true; progressIndicator.IsVisible = true; // 模拟后台耗时任务拉取数据的场景 Task.Factory.StartNew(async () => { await Task.Delay(3000); // 调用UI线程添加数据 this.Dispatcher.BeginInvoke(() => { int count = Items.Count; for (int i = count; i < count + 50; i++) { Items.Add(new Item { FirstName = "Li" + i, LastName = "Lei" + i }); } // 关闭进度条 progressIndicator.IsVisible = false; // 修改加载的状态 IsLoading = false; }); }); } } } } } }