Связывание данных работает через интерфейс с именем 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
![Xaminar](https://i.stack.imgur.com/XCVKl.png)
Чтобы использовать этот интерфейс для небольшого списка в памяти - например. менее 1000 «маленьких» объектов — все, что вам нужно сделать, это изменить List<T>
на ObservableCollection<T>
— 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 разработан как однопоточный, поэтому убедитесь, что все изменения в коллекции выполняются в потоке пользовательского интерфейса, а не в рабочем потоке. Если вам нужно, вы можете вернуться к потоку пользовательского интерфейса, используя
InvokeOnMainThread(() => { /* do work here */ })
в ViewModel.
- что в Android способ работы списков (через базовый AdapterView) означает, что каждый раз, когда вы вызываете какое-либо обновление в ObservableCollection, тогда список пользовательского интерфейса будет игнорировать подсказку действия (Добавить, Удалить и т. д.) - он будет рассматривать каждое изменение как сброс и это приведет к перерисовке всего списка.
Для больших коллекций, когда вы не хотите, чтобы все элементы находились в памяти одновременно, вам может потребоваться реализовать некоторый список, поддерживаемый хранилищем данных, самостоятельно.
В https://github.com/slodge/MvvmCross/blob/vnext/Sample%20-%20SimpleDialogBinding/SimpleDroidSql.Core/DatabaseBackedObservableCollection.cs
Эта виртуализация данных коллекции распространена в приложениях WP и WPF, например. см. вопросы и ответы, такие как Список виртуализируется по умолчанию в WP7 Манго?
person
Stuart
schedule
21.12.2012