【问题标题】:Can't bind a MvxBindableListView in TwoWay Mode无法在 TwoWay 模式下绑定 MvxBindableListView
【发布时间】:2012-12-21 09:56:43
【问题描述】:

我正在尝试在 TwoWay 模式下绑定一个 MvxBindableListView,以便当我在ViewModel(通过按钮的单击命令)。 目前它只在布局在 start/tabchange 完全加载时更新...

ViewModel 是:

public List<MyType> TestList
        {
            get { return _testList; }
            set
            {
                _testList = value;
                FirePropertyChanged("TestList");
            }
        }

视图中的.axml是:

<Mvx.MvxBindableListView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        local:MvxBind="{'ItemsSource':{'Path':'TestList','Mode':'TwoWay'}}"
        local:MvxItemTemplate="@layout/my_item_layout" />

【问题讨论】:

    标签: android mvvm xamarin.android mvvmcross inotifycollectionchanged


    【解决方案1】:

    数据绑定的工作方式是通过一个名为INotifyPropertyChanged的接口

    在此界面中发生的情况是,每当属性更改时,ViewModel 都会向 View 发送消息 - 例如

        FirePropertyChanged("TestList");
    

    对于列表,如果列表本身的内容发生变化,这将无济于事 - 例如当列表添加或删除项目时。


    为了解决这个问题,.Net Mvvm 实现包括另一个接口INotifyCollectionChanged

    一个集合——比如一个列表——可以实现INotifyCollectionChanged,以便让视图知道集合的内容何时发生变化。

    例如,集合可能会触发包含以下提示的事件:

    • 一切都变了 - NotifyCollectionChangedAction.Reset
    • 已添加一项 - NotifyCollectionChangedAction.Add
    • 项目已被删除 - NotifyCollectionChangedAction.Remove
    • ...

    大约 12:30 到 MvvmCross Xaminar http://www.youtube.com/watch?v=jdiu_dH3z5k 有一个关于这个界面的简短介绍


    将此接口用于内存中的小型列表 - 例如少于 1000 个“小”对象 - 您只需将 List&lt;T&gt; 更改为 ObservableCollection&lt;T&gt; - ObservableCollection 是来自核心 .Net 库(来自 Microsoft 或 Mono)的一个类,它将触发正确的事件当您添加/删除列表项时。

    您可以在以下位置查看 Mono ObservableCollection 实现的源代码:https://github.com/mosa/Mono-Class-Libraries/blob/master/mcs/class/System/System.Collections.ObjectModel/ObservableCollection.cs - 值得花一些时间查看此实现,以便您可以更多地了解 Mvvm 如何与 INotifyCollectionChanged 一起工作。

    如果你使用 ObservableCollection 类,那么你的代码会变成:

        private ObservableCollection<MyType> _testList;
        public ObservableCollection<MyType> TestList
        {
            get { return _testList; }
            set
            {
                _testList = value;
                FirePropertyChanged("TestList");
                // in vNext use RaisePropertyChanged(() => TestList);
            }
        }
    

    与:

     <Mvx.MvxBindableListView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        local:MvxBind="{'ItemsSource':{'Path':'TestList'}}"
        local:MvxItemTemplate="@layout/my_item_layout" />
    

    注意:

    • 绑定是OneWay - 这意味着绑定仍然只是从 ViewModel 到 View - 从 View 到 ViewModel没有更新。
    • ObservableCollection 被设计为单线程 - 因此请确保对集合的所有更改都在 UI 线程上完成 - 而不是在工作线程上完成。如果需要,您可以在 ViewModel 中使用 InvokeOnMainThread(() =&gt; { /* do work here */ }) 重新编组到 UI 线程。
    • 在 Android 中,列表的工作方式(通过基本 AdapterView)意味着每次您在 ObservableCollection 上调用任何更新时,UI 列表都会忽略操作提示(添加、删除等) - 它会处理每个更改作为重置,这将导致整个列表重绘。

    对于较大的集合 - 您不希望所有项目同时在内存中 - 您可能需要自己实现一些数据存储支持的列表。

    https://github.com/slodge/MvvmCross/blob/vnext/Sample%20-%20SimpleDialogBinding/SimpleDroidSql.Core/DatabaseBackedObservableCollection.cs 中有一个简单的 sqlite 数据支持存储的简短示例

    这种收集数据的虚拟化在 WP 和 WPF 应用程序中很常见 - 例如。查看Is listbox virtualized by default in WP7 Mango?之类的问题和答案

    【讨论】:

    • 被推荐的视频好像移动了here
    【解决方案2】:

    我们刚刚找到了一个适合我们的解决方法!!

    注意:在列表中添加和删除会使用新/删除的项目更新视图。但是,对现有项目状态的任何更改都没有反映出来。

    解决方案:我们清除了列表并将项目重新添加到具有更新状态的 ViewModel 属性中。然后调用 raisepropertychanged 模拟双向绑定行为。从本质上讲,它是删除所有值并重新添加所有值。

    【讨论】:

      猜你喜欢
      • 2011-08-10
      • 2016-09-10
      • 1970-01-01
      • 1970-01-01
      • 2017-02-24
      • 1970-01-01
      • 2016-10-26
      • 2010-10-10
      • 2010-12-26
      相关资源
      最近更新 更多