gpt4 book ai didi

listview - 如何将列表项绑定(bind)到它是否包含在另一个集合中

转载 作者:行者123 更新时间:2023-12-04 16:03:42 25 4
gpt4 key购买 nike

场景是我们有一个显示在列表中的项目列表(Android 上的 ListView 和 iOS 上的 UITableView)。 ItemSource 来自网络服务。除了项目的数据属性之外,每个项目都有额外的状态,可以将其添加到当前选定项目的集合中,该集合反射(reflect)在 View 模型的另一个集合中。

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

为绑定(bind)指定的数据上下文是来自 ItemsSource 的数据,它只是项目的原始数据,无法知道该数据是否是当前选定的项目之一。这必须通过询问 ViewModel 来完成。

我正在努力寻找解决此问题的最佳方法。我当然不想修改 ItemsSource 以将虚假属性添加到源中的每个项目。

我可以通过覆盖 Adapter/TableViewSource 对其进行硬编码而不实际为此使用绑定(bind)来破解它,但这似乎是错误的。

更新

这个解释得不是很好,所以让我尝试使用现有的 MvvmCross 示例作为基础进行解释。

考虑 N=6 和 N=7 的图书样本。我们想添加一项新功能,我们可以在其中标记我们已经拥有的图书,对于我们已标记的图书,它会显示一个指示器,告诉您您拥有这本书。

假设 View 模型有如下方法:

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

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

我想弄清楚如何在 ListViewItem/TableViewCell 上设置绑定(bind),以便它可以使用项目的 DataContext 中的 ID 查询 ViewModel 上的 IsOwned 方法,以控制其中的 UI 元素的可见性记录。

我猜我必须创建一个自定义源绑定(bind),但该绑定(bind)必须引用 ViewModel 和 DataContext,所以我在这里有点迷路。

请注意,在我试图解决的实际问题中,某些内容是否被标记的状态是临时的,并且仅对 ViewModel 是本地的(如果我退出屏幕,则不会被记住)。这排除了使用服务来获取信息的想法。

最佳答案

您的 UI 列表项单元格有一个 DataContext,它的控件绑定(bind)到该 DataContext - DataContext 是该单元格自己的单独 ViewModel。

MvvmCross(从今天的 v3.1 开始)不允许您查看 DataContext 之外的内容 - 它不允许您(例如)检查另一个 UIElement 的 DataContext 或不允许您请求 Parent。

为此,我通常为我的列表项单元格创建我的 DataContext,以便它们包含这些单元格所需的所有数据和操作 - 这样它们就真正成为列表项 View 的 ViewModel。如果有一些方便的模型类可以重用,那么这通常意味着我创建一个包装类来协助 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>作为属性 - 然后单个列表项单元格可以绑定(bind)到 IsSelected以及底层对象的链接属性,如 Foo.Name .

从架构上讲,这种模式是健壮的、可测试的、干净的并且是“正确的”,因为每个列表项单元格都有自己定义明确的 ViewModel。但是,我确实理解它可能感觉有点代码繁重 - 它可能感觉有点矫枉过正。在某些情况下,开发人员只想直接使用 Model 类而无需 ViewModel 步骤。也许在 Mvx 的某个 future 版本中,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();
}
}

这可以用于绑定(bind)像 ItemsSource FooWrapping(SourceList, .) 这样的表达式- 但在动态情况下(列表经常更改)要小心使用它,因为这可能很慢。

关于listview - 如何将列表项绑定(bind)到它是否包含在另一个集合中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22695039/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com