listview – 如何将列表项绑定到是否包含在另一个集合中

场景是我们有列表中显示的项目列表(Android上的ListView和iOS上的UITableView). ItemSource来自Web服务.除了项目的数据属性之外,每个项目都具有附加状态,可以将其添加到当前所选项目的集合中,这些项目将反映在视图模型上的另一个集合中.

我需要能够根据它是否在当前选定的列表中来更改列表中项目的显示.

为绑定提供的datacontext是来自ItemsSource的数据,它是项目的原始数据,并且无法知道该数据是否是当前所选项目之一.这必须通过询问ViewModel来完成.

我很难找到解决这个问题的最佳方法.我当然不想修改ItemsSource来为源中的每个项添加一个伪属性.

我可以通过覆盖Adapter / TableViewSource对其进行硬件编码来对其进行硬编码而不实际使用绑定,但这似乎是错误的.

更新

这没有得到很好的解释,所以让我尝试解释使用现有的MvvmCross示例作为基础.

考虑N = 6和N = 7的书籍样本.我们想要添加一个新功能,我们可以在其中标记我们已经拥有的书籍,并且我们标记的书籍会显示一个指示符,告诉您自己拥有该书.

想象一下,视图模型具有以下方法:

public bool IsOwned(string id)
public void SetOwned(string id, bool owned)

这些讨论的实现并不重要,但我可能还需要某种形式的事件处理程序来通知书籍的所有权发生了变化.

我试图找出如何在ListViewItem / TableViewCell上设置绑定,以便它可以使用DataContext中的ID来查询ViewModel上的IsOwned方法,以控制该记录中UI元素的可见性.

我猜我将不得不创建一个自定义源绑定,但该绑定必须引用ViewModel和DataContext,所以我在这里有点迷失.

请注意,在我试图解决的实际问题中,是否标记的内容的状态是临时的,仅限于ViewModel本地(如果我退出屏幕则不记得).这排除了获得服务以获取信息的想法.

您的UI列表项单元格具有其控件绑定到的DataContext – DataContext是单元格自己的单独ViewModel.

MvvmCross没有(从今天的v3.1开始)让你看看DataContext以外 – 它不会让你(例如)检查另一个UIElement的DataContext或者不让你要求父.

为了解决这个问题,我通常会为列表项单元格创建DataContext,以便它们包含这些单元格所需的所有数据和操作 – 这样它们就是列表项视图的ViewModel.如果有一些方便的Model类可以重用,那么这通常意味着我创建了一个包装类来协助DataContext.偶尔(很少)我会在ValueConverter中执行此操作(见下文)*,但一般情况下我会使用ViewModel公开的包装类来完成此操作.

例如,对于类似你的情况,如果我有一个List< Foo>作为我的核心模型,然后在页面级ViewModel中我将创建一个FooWithSelectionState类:

public class FooWithSelectionState : MvxNotifyPropertyChanged
{
    public Foo Foo { get; set; /* normal INPC in here */ }
    public bool IsSelected { get; set; /* normal INPC in here */ }
}

这将允许我的ViewModel公开List< FooWithSelectedState>作为属性 – 单个列表项单元格然后可以绑定到IsSelected以及底层对象的链接属性,如Foo.Name.

在架构上,这种模式是健壮的,它是可测试的,它是干净的并且它是“正确的”,因为每个列表项单元格都有自己定义明确的ViewModel.但是,我确实理解它可能感觉有点代码重 – 它可能感觉有点矫枉过正.在某些情况下,开发人员只想在没有ViewModel步骤的情况下直接使用Model类.也许在Mvx的某个未来版本中,MvvmCross可能会添加一些替代机制来允许DataBound UI元素在其自己的DataContext之外查看 – 这已在例如https://github.com/MvvmCross/MvvmCross/issues/35 – 但今天这不存在(我知道)

如果你确实想使用ValueConverter路由,那么这样做的一种方法是在ItemsSource上使用ValueConverter – 例如,类似于:

public class FooWrappingValueConverter : MvxValueConverter<IList<Foo>, IList<FooWithSelectionState>>
{
     protected override IList<FooWithSelectionState> Convert(IList<Foo> value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
         var viewModel = parameter as MyViewModel;

         return value.Select(f => new FooWithSelectionState()
                                       {
                                          Foo = f,
                                          IsSelected = viewModel.IsSelected(f)
                                       })
                     .ToList();
     }
}

这可以用于与诸如ItemsSource FooWrapping(SourceList,.)之类的表达式进行绑定 – 但是在动态情况下(列表经常更改)时要小心使用它,因为这可能很慢.

https://stackoverflow.com/questions/22695039/how-to-binding-list-item-to-whether-it-is-contained-in-another-collection

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:listview – 如何将列表项绑定到是否包含在另一个集合中