Не удается связать MvxBindableListView в двухстороннем режиме

Я пытаюсь связать MvxBindableListView в режиме TwoWay, чтобы он обновлялся в View, когда я устанавливаю его значение в ViewModel (через команду Click кнопок). В настоящее время он обновляется только тогда, когда макет полностью загружен при запуске / изменении вкладок...

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" />

person Ivozor    schedule 21.12.2012    source источник


Ответы (2)


Связывание данных работает через интерфейс с именем 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


Чтобы использовать этот интерфейс для небольшого списка в памяти - например. менее 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
comment
Похоже, что указанное видео перемещено сюда. - person Runar Jordahl; 06.04.2015

Мы только что нашли обходной путь для этого, который работает для нас!!

ПРИМЕЧАНИЕ. Добавление и удаление из списка обновляет представление новым/удаленным элементом. Однако какие-либо изменения в состоянии существующих элементов не были отражены.

РЕШЕНИЕ. Мы очистили наш список и повторно добавили элементы в свойство ViewModel с обновленным состоянием. Вызов raisepropertychanged затем имитирует двустороннее поведение привязки. По сути, это удаление всех значений и повторное добавление всех значений.

person user3334681    schedule 11.03.2016