使用Mvvmcross进行UITableView分组的现代方法 [英] Modern approach for UITableView grouping with Mvvmcross

查看:37
本文介绍了使用Mvvmcross进行UITableView分组的现代方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现了几种(不是太多)不同的方法来对Xamarin + mvvmcross中的细胞进行分组.我已经尝试了其中的几个,但是遇到了一个问题:当我的真实服务返回更新的collection(延迟很小)时,绑定实际上并没有起作用,并且列表仍然为空.如果要运行假服务,该服务立即返回结果,则列表中会填充数据.

I had found several (not too many) different approaches for grouping cells in Xamarin+mvvmcross. I've tried couple of them, but i'm getting a problem: when my real service returns updated collection (with a small delay), binding is not really working and list remains empty. If to run fake service, which returns result instantly, list is filled with data.

我尝试了几种方法,但是没有人推动我前进,因此我不确定是否需要任何代码.只是问是否有示例/提示可以对分组进行现代化实施.

I've tried several approaches, but no one pushed me forward, so i'm not sure if any code is necessary. Just asking if there's a sample/hints for the modern implementation of the grouping.

这是一个代码示例.当前版本基于Stuart的答案:

here's a code sample. Current version is based on Stuart's answer: Unable to bind to ios table section cells in mvvmcross, child cells bind as expected

ViewModel:

ViewModel:

    public override async void OnShow()
    {
        var calendarList = await DataService.GetListAsync();

        CalendarList = new List<Model>(calendarList.OrderBy(a => a.Date));
    }

因此,viewmodel获取一个Models列表,按Date排序并将其设置为CalendarList. CalendarList只是一个引发通知的列表(新功能正在执行此工作).

So, viewmodel gets a list of Models, order it by Date and set it to CalendarList. CalendarList is just a List which throws notifications (new is doing this job).

查看,初始化:

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        var source = new TableSource(CalendarList);

        this.AddBindings(new Dictionary<object, string>
        {
            {source, "ItemsSource CalendarList" }
        });

        CalendarList.Source = source;
        CalendarList.ReloadData();
    }

视图,TableSource

View, TableSource

    public class TableSource : MvxSimpleTableViewSource
    {
        private static readonly NSString CalendarCellIdentifier = new NSString("CalendarCell");
        private List<IGrouping<DateTime, Model>> GroupedCalendarList;

        public TableSource(UITableView calendarView) : base(calendarView, "CalendarCell", "CalendarCell")
        { 
        }


        public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            var foo = GroupedCalendarList[indexPath.Section].ToList();
            var item = foo[indexPath.Row];

            var cell = GetOrCreateCellFor(tableView, indexPath, item);

            var bindable = cell as IMvxDataConsumer;
            if (bindable != null)
                bindable.DataContext = item;

            return cell;
        }

        public override nint RowsInSection(UITableView tableview, nint section)
        {
            var numberRows = GroupedCalendarList[(int)section].Count();
            return numberRows;
        }

        public override UIView GetViewForHeader(UITableView tableView, nint section)
        {
            var label = new UILabel();
            label.Text = GroupedCalendarList[(int)section].FirstOrDefault().ScheduledStart.Value.Date.ToString();
            label.TextAlignment = UITextAlignment.Center;

            return label;
        }

        public override nint NumberOfSections(UITableView tableView)
        {
            return GroupedCalendarList.Count;
        }

        public override void ReloadTableData()
        {
            if (ItemsSource == null) return;
            var calendarList = new List<Model>(ItemsSource as List<ActivityModel>);

            List<IGrouping<DateTime, Model>> groupedCalendarList = calendarList.GroupBy(cl => cl.ScheduledStart.Value.Date).ToList();

            if (ItemsSource != null)
                GroupedCalendarList = new List<IGrouping<DateTime, Model>>(groupedCalendarList);
        }
    }

症状之一是VM更新列表时未调用ReloadTableData().

One of the symptoms is that ReloadTableData() is not called when VM is updating the list.

好吧,我尝试使用ObservableCollection,并且看到ReloadTableData被调用了,但是UI仍然是空的.如果有人可以提供有效的样本,那就太好了.

EDIT 2: well, i've tried to use ObservableCollection and i saw that ReloadTableData is called, but UI is still empty. If anyone can provide a working sample - that'd be great.

更新的VM:

    public override async void OnShow()
    {
        var calendarList = await DataService.GetListAsync();

        CalendarList.Clear();
        foreach (var item in calendarList.OrderBy(a => a.ScheduledStart.Value.Date))
        {
            CalendarList.Add(item);  // Lets bruteforce and send notification on each add. In real life it's better to use extension ObservableCollection.AddRange().
        }
    }

更新后的视图:

public override void ReloadTableData()
        {
            if (ItemsSource == null) return;
            var calendarList = ItemsSource as IEnumerable<Model>;

            var groupedCalendarList = calendarList.GroupBy(cl => cl.ScheduledStart.Value.Date).ToList();

            GroupedCalendarList = new List<IGrouping<DateTime, Model>>(groupedCalendarList);

            Mvx.Trace("Trying to add new item " + calendarList.Count());
        }

在这种情况下,输出充满

In that case, output is full of

诊断:9.54尝试添加新项目77

Diagnostic: 9.54 Trying to add new item 77

但是用户界面列表仍然为空.

But the UI list is still empty.

如果要通过添加Task.Run().Wait()替换VM.OnShow();到虚拟机的ctor(这样会延迟View.ViewDidLoad()直到加载数据)-然后列表正确显示.

If to replace VM.OnShow() with adding Task.Run().Wait(); to the VM's ctor (so it would delay View.ViewDidLoad() until data is loaded) - then list shows correctly.

public ViewModel()
    {
        Task.Run(async () =>
        {
            var calendarList = await DataService.GetListAsync();
            CalendarList = new ObservableCollection<ActivityModel>(calendarList);
        }).Wait(); // This guy is called before View.ViewDidLoad() and grouped list is shown properly
    }

推荐答案

我是盲人!感谢 MvvmCross Slack频道的@nmilcoff指出了问题所在.我忘了打电话给base.ReloadTableData().

I'm blind! Thanks to @nmilcoff from MvvmCross Slack channel for highlighting the problem. I forgot to call base.ReloadTableData().

当然还要感谢Pilatus和Springham的良好提示.

And of course thanks for Pilatus and Springham for good hints.

这是解决方案:

    public override void ReloadTableData()
    {
        if (ItemsSource == null) return;
        var calendarList = new List<Model>(ItemsSource as List<ActivityModel>);

        List<IGrouping<DateTime, Model>> groupedCalendarList = calendarList.GroupBy(cl => cl.ScheduledStart.Value.Date).ToList();

        if (ItemsSource != null)
            GroupedCalendarList = new List<IGrouping<DateTime, Model>>(groupedCalendarList);

        base.ReloadTableData(); // Here we are
    }

这篇关于使用Mvvmcross进行UITableView分组的现代方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆