【问题标题】:How to implement Loading Incrementally (ItemAppearing) Items in ListView using MVVM in Xamarin Forms?如何在 Xamarin Forms 中使用 MVVM 在 ListView 中实现增量加载(ItemAppearing)项目?
【发布时间】:2021-09-26 02:44:08
【问题描述】:

我有一个ListView,其中使用ItemAppearing 逐步添加项目。我希望它通过我的 ViewModel 来实现它。 ItemAppearing 仅从 View.cs 调用一个方法,因此,有什么方法可以在我的 ViewModel 类中实现它。

请注意,从 View.cs 添加项目时,我可以逐步加载项目。我只想从 ViewModel 加载更多项目。

这是我的 XAML 代码:

<ListView ItemsSource="{Binding JobsList}" HasUnevenRows="True" 
          SelectedItem="{Binding SelectedJob}" ItemAppearing="LoadMoreItems">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Label Text="{Binding Title}" />
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

【问题讨论】:

  • @Jason,是的,我知道,但我想使用ListView。同样在ListView 中,我们可以使用ViewCell 提供我在CollectioView 中无法实现的涟漪效果。
  • 然后只需从事件处理程序中调用您的 VM 方法,或使用 EventToCommand

标签: c# xaml xamarin xamarin.forms mvvm


【解决方案1】:

如果您(在您的问题中)添加有关您正在尝试做的事情的更多详细信息,那将是最好的。

以下技术模糊了“View 做什么”和“ViewModel 做什么”之间的界限 - 并将您的 View 和您的 ViewModel “紧密结合” - 可能有更好的方法来实现您的目标。不过,这是一个有用的技术,所以我会展示它。


Jason 的评论“从事件处理程序调用你的 VM 方法”的详细信息。

向你的虚拟机添加一个公共方法:

public class MyVM
{
    public void MyMethod() {
        // whatever you need to do to prepare the item.
    }
}

在 LoadMoreItems 中,调用该方法:

((MyVM)BindingContext).MyMethod();

根据需要添加参数。

如果您需要“回调”视图中的方法,请通过操作参数执行此操作:

public void MyMethod(Action<...> action) {
    ...
    action(...);
}

更多细节,google C#将Action作为参数传递。


还有其他用于在 View 和 ViewModel 之间进行通信的技术 - 搜索有关该主题的更多信息。

【讨论】:

    【解决方案2】:

    这个答案会比较长,但你不会在其他任何地方找到它。我已经尝试了 2 天。

    这个答案很长,因为我已经证明了 3 件事:

    • ItemAppearing 绑定到Command,然后逐步加载项目。
    • ListView 中选择一个项目并显示它。
    • 在增量加载新项目时显示动画。

    MVVM 中,ViewModel 应该不知道 View。因此,ViewModel 必须不知道 View 内的 ListView 是否滚动到最后一项,或者是否应在滚动时调用 LoadMoreItems

    我们需要将ItemAppearing事件转换为Command并将这个命令绑定到ItemAppearing事件。

    为此,我们需要安装 Xamarin.CommunityToolkit Nuget 包。此软件包受 .NetFoundationXamarin 社区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));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-27
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      相关资源
      最近更新 更多