这个答案会比较长,但你不会在其他任何地方找到它。我已经尝试了 2 天。
这个答案很长,因为我已经证明了 3 件事:
- 将
ItemAppearing 绑定到Command,然后逐步加载项目。
- 从
ListView 中选择一个项目并显示它。
- 在增量加载新项目时显示动画。
在 MVVM 中,ViewModel 应该不知道 View。因此,ViewModel 必须不知道 View 内的 ListView 是否滚动到最后一项,或者是否应在滚动时调用 LoadMoreItems。
我们需要将ItemAppearing事件转换为Command并将这个命令绑定到ItemAppearing事件。
为此,我们需要安装 Xamarin.CommunityToolkit Nuget 包。此软件包受 .NetFoundation、Xamarin 社区 和 Microsoft 支持,由 Microsoft 编写。这是官方包,是大多数高级 Xamarin.Forms 所必需的。在 Nuget.org 上查看更多信息,下载最新的稳定版本:https://www.nuget.org/packages/Xamarin.CommunityToolkit(安装在所有共享项目中,Android、iOS、UWP、WPF、Tizen 等)
假设您的模型:
public class Job
{
public int Id { get; set; }
public string Title { get; set; }
}
现在在您的 XAML 中
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
...
xmlns:xct="http://xamarin.com/schemas/2020/toolkit">
<StackLayout>
<RefreshView IsRefreshing="{Binding IsLoading}">
<ListView ItemsSource="{Binding JobsList}" SelectedItem="{Binding SelectedJob}">
<ListView.Behaviors>
<xct:EventToCommandBehavior EventName="ItemAppearing"
Command="{Binding LoadMoreItemsCommand}"
CommandParameter="{Binding ItemVisibilityEventArgs}"/>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Id}" />
<Label Text="{Binding Title}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
在后面的代码中将 BindingContext 设置为 ViewModel 的实例
public partial class ListPage : ContentPage
{
ListPageViewModel ListPageVM;
public JobsListPage()
{
InitializeComponent();
ListPageVM = new ListPageViewModel();
BindingContext = ListPageVM;
}
}
在您的 ViewModel 中
public class ListPageViewModel : INotifyPropertyChanged
{
public ObservableCollection<Models.Job> JobsList
{
get { return jobsList; }
set { jobsList = value; OnPropertyChanged(nameof(JobsList)); }
}
public ICommand LoadMoreItemsCommand { get; private set; }
// Used to show Loading Animation in Refresh View
public bool IsLoading
{
get { return isLoading; }
set { isLoading = value; OnPropertyChanged(nameof(IsLoading)); }
}
public Models.Job SelectedJob
{
get { return selectedJob; }
set
{
if (value != null)
{
selectedJob = value;
var page = Application.Current.MainPage;
page.DisplayAlert("Alert", $"Selected: {selectedJob.JobTitle}", "OK");
OnPropertyChanged(nameof(SelectedJob));
}
}
}
ObservableCollection<Models.Job> jobsList;
Models.Job selectedJob;
bool isLoading;
public ListPageViewModel() // ViewModel Constructor
{
// Initialize your List
JobsList = new ObservableCollection<Models.Job>
{
new Models.Job() { Id = 0001, Title = "Product Manager" },
new Models.Job() { Id = 0002, Title = "Senior Executive" },
}
LoadMoreItemsCommand = new Command<ItemVisibilityEventArgs>(
execute: async (ItemVisibilityEventArgs args) =>
{
if ((args.Item as Models.Job).Id >= JobsList[JobsList.Count - 1].Id)
{
IsLoading = true;
for (int i = 0; i < 10; i++)
{
JobsList.Add(new Models.Job()
{
Id = JobsList.Count + 1, JobTitle = JobsList[i].Title
});
}
await System.Threading.Tasks.Task.Delay(2000); // Fake delay
IsLoading = false;
}
});
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}