有些時候,當使用者要查詢後端資料庫的資料時候,因為所設定的查詢條件過於寬鬆,將會導致會從後端資料一次性的接收到成千上萬筆的資料,若您讓手機應用程式來接收這麼多的資料,將會有嚴重的效能上的問題出現,例如,要從網路一次讀取到這麼多的資料,會需要花點時間;要把這麼多的紀錄加入到 ListView 中,也有可能造成記憶體不足或者ListView操作延緩的現象產生。
在這個時候,我們就可以使用
延遲載入
Lazy Loading
這樣的設計方法來解決此一問題。他的處理方式為,每次呼叫 Web API 的時候,後端 Web API 僅僅會回傳一定數量的紀錄(例如:最多 100 筆),當使用者捲動 ListView 的清單到最後一筆紀錄的時候,您的 Xamarin.Forms 程式,就會再度呼叫 Web API 服務,請求回傳接下來一定數量的紀錄(例如:101~200筆),並且把這些新讀取到的紀錄,顯示到 ListView 中。
想要做到這樣的功能,ListView 有提供兩個事件,ItemAppearing / ItemDisappearing 這兩個事件,可以供我們做出這樣的效果;在我們接下來的範例中,將會展示出這樣的設計方法。
我們透過了 XAML 的行為 Behavior (這裡的行為擴充,我們將會使用 Prism 所提供的擴充行為功能),設定當
ItemAppearing
事件發生的時候,會執行所對應的指定的 ViewModel 內的命令 ItemAppearingCommand
,而我們在 ViewModel 內,將會設計,當這個命令 ItemAppearingCommand
被觸發的時候,並且現在所顯示的紀錄是全部紀錄的最後一筆,將會進行載入更多的紀錄到 ListView 內(這裡我們將會呼叫 Reload(fooLast.ID+1)
方法來達成)。
因此,在這個範例中,也充分展示出,如何不透過
後置碼
Code Behind 的設計技術,也可以在 ViewModel 內,處理相關事件發生要處理的需求。
當然,為了簡化這個範例專案的複雜程度,我們要讀取的集合資料,並不會實際從網路呼叫 Web API 來取得,而是直接產生靜態的集合資料(若您要設計每次都從網路讀取資料,請記得要設計相關的 UX,告知使用者,現在這樣更新資料中,要不然,當在讀取更多資料的時候,手機應用程式,當時會卡卡的)。
底下是我們這個測試頁面 View 的 XAML 標記語言
我們首先宣告了一個 Prism Behavior 的命名空間
xmlns:behavior="clr-namespace:Prism.Behaviors;
接著在 ListView 內,加入一個行為設計,EventToCommandBehavior
,並且指定當 ItemAppearing
事件發生的時候,就會需要執行 ViewModel 內的 ItemAppearingCommand
命令;另外,在這裡,我們使用了 EventArgsParameterPath
這個屬性,設定當觸發這個 ViewModel 內的命令時候,需要將是事件中的這個參數,傳入到命令中,這樣,我們才可以在該命令中,知道當時正在顯示的紀錄是哪一筆。<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
xmlns:behavior="clr-namespace:Prism.Behaviors;assembly=Prism.Forms"
x:Class="XFListViewLazy.Views.MainPage"
Title="MainPage">
<Grid
>
<ListView
ItemsSource="{Binding MyDatas}"
SelectedItem="{Binding SelectedMyData}"
HasUnevenRows="True"
>
<ListView.Behaviors>
<behavior:EventToCommandBehavior
EventName="ItemAppearing"
Command="{Binding ItemAppearingCommand}"
EventArgsParameterPath="Item"/>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding ID}"/>
<Label Text="{Binding Name}" FontSize="30"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ContentPage>
底下是上面 View 的相對應 ViewModel
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using Xamarin.Forms;
using XFListViewLazy.Models;
using XFListViewLazy.Repositories;
namespace XFListViewLazy.ViewModels
{
public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<MyModel> MyDatas { get; set; } = new ObservableCollection<MyModel>();
public MyModel SelectedMyData { get; set; }
private readonly INavigationService _navigationService;
public MyRepository _myRepository { get; set; }
public DelegateCommand<MyModel> ItemAppearingCommand { get; set; }
public MainPageViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
_myRepository = MyRepository.GetInstance();
ItemAppearingCommand = new DelegateCommand<MyModel>((x) =>
{
var fooLast = MyDatas.Last();
if (x.ID == fooLast.ID)
{
Reload(fooLast.ID+1);
}
});
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatingTo(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
Reload(0);
}
public void Reload(int last)
{
var foo = _myRepository.GetNext(last);
foreach (var item in foo)
{
MyDatas.Add(item);
}
}
}
}
沒有留言:
張貼留言