Привязка EventToCommand с параметрами в моделях переносимого представления

Я реализую модель представления, которая используется приложениями на нескольких платформах. Я использую MvvmCross v3, у которого есть собственный класс MvxEventToCommand, но я считаю, что проблема такая же для других фреймворков, таких как MVVM Light. Пока событие используется без параметров, реализация проста, и это относится к простым взаимодействиям, таким как касание элемента управления.

Но когда команде необходимо обрабатывать аргументы событий, все становится сложнее. Например, модель представления должна реагировать на определенные изменения полосы прокрутки (и загружать дополнительные элементы в связанное представление списка). Вот пример XAML:

<cmd:EventToCommand 
    Command="{Binding ScrollChanged}" 
    CommandParameter="{Binding EventArgs}" />

(MvvmCross использует MvxEventToCommand, но принцип тот же).

Тогда в моей модели у меня может быть следующий обработчик команд:

public ICommand ScrollChanged
{
    get
    {
        return new RelayCommand<ScrollChangedEventArgs>(e =>
        {
            MessageBox.Show("Change!");
        });
    }
}

(MvxCommand в MvvmCross).

Проблема в том, что ScrollChangedEventArgs зависит от платформы, и этот код просто не скомпилируется в переносимой библиотеке классов. Это общая проблема с любой командой, которая требует не только отправки при запуске события, но и более конкретных сведений о событии. Перемещение этого кода в специфичную для платформы часть глупо, потому что это более или менее убивает концепцию переносимых моделей представлений и представлений без кода программной части. Я попытался найти проекты, в которых модели представления используются на разных платформах, но все они используют простые события, такие как «Tap», без прикрепленных сведений о событии.

ОБНОВЛЕНИЕ 1 Я согласен с замечанием Стюарта о том, что модели представления должны иметь дело только с абстракциями более высокого уровня, поэтому я перефразирую первоначальную проблему: как сопоставить результаты низкоуровневых взаимодействий с платформо-нейтральным событием, которое запускает команда бизнес-логики? Рассмотрим приведенный выше пример: команда бизнес-логики — «загрузить больше элементов в список», т. е. мы имеем дело с виртуализацией списка, когда изначально загружается ограниченное количество элементов из большой коллекции, и прокрутка вниз до конца списка должна вызывают загрузку дополнительных элементов.

WinRT может позаботиться о виртуализации списков, используя наблюдаемые коллекции, поддерживающие интерфейс ISupportIncrementalLoading. Среда выполнения обнаруживает эту возможность и автоматически запрашивает дополнительные элементы из соответствующей службы, когда пользователь прокручивает список вниз. На других платформах эта функция должна быть реализована вручную, и я не могу найти другого способа, кроме как реагировать на событие ScrollViewer ScrollChanged. Тогда я вижу еще два варианта:

  • Поместите обработчик OnScrollChanged в файл кода программной части и вызовите событие более высокого уровня переносимой модели представления (например, «OnItemsRequested»);
  • Избегайте кода программной части и изо всех сил пытайтесь связать событие ScrollChanged напрямую с моделью представления, тогда нам сначала нужно будет переназначить событие для конкретной платформы.

Пока нет поддержки второго варианта, размещение обработчика событий в файле кода программной части допустимо, если это делается с единственной целью сопоставления событий. Но я хотел бы исследовать, что можно сделать, используя второй вариант. У MvvmCross есть класс MapCommandParameter, который, похоже, может помочь, поэтому мне интересно, следует ли мне использовать его.

ОБНОВЛЕНИЕ 2 Я попробовал подход MapCommandParameter, и он сработал, позволив мне вставить адаптер для конкретной платформы, который будет сопоставлять низкоуровневые события для просмотра команд, специфичных для модели. Так что второй вариант сработал без проблем. Стюарт также предложил подклассы listview, поэтому нет необходимости заботиться о событиях прокрутки. Я планирую поиграть с ним позже.


person Vagif Abilov    schedule 07.04.2013    source источник


Ответы (1)


Я согласен с тем, что команды модели представления обычно должны быть выражены с точки зрения концепций модели представления, поэтому было бы «странно» отправлять модели представления команду об изменении значения полосы прокрутки, но может быть нормально отправить модель представления команду о том, что пользователь выбирает определенные список элементов, которые должны быть видны (что она делает с помощью прокрутки)

Один из примеров, когда я делал подобные вещи ранее, — это выбор списка.

Первоначально я сделал это на нескольких платформах, используя кросс-платформенный объект eventargs -

затем это использовалось в WindowsPhone (например) через класс EventToCommand, такой как rel="nofollow">https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.WindowsPhone/Commands/MvxSelectionChangedEventToCommand.cs

Однако... я должен признать, что этот код использовался не так часто... Для выбора списка мы вместо этого в основном использовали привязку selecteditem, и просто не было приложений, которые нуждались бы в более сложных параметризованных командах (до сих пор ) — вам даже может понадобиться вернуться к очень старому коду v1 mvvmcross, чтобы найти примеры, в которых он используется.

person Stuart    schedule 07.04.2013
comment
Спасибо @Stuart, я расширил пост, рассказав, как я понимаю, что этого можно достичь. По сути, это выбор между размещением картографов событий в программном коде или использованием класса MvvmCross MapCommandParameter. Я полностью согласен с тем, что детали событий для конкретной платформы не относятся к модели представления. - person Vagif Abilov; 07.04.2013
comment
Не могу ответить - время взлета самолета. Но для загрузки большего рассмотрите возможность создания подкласса listview, чтобы он мог запускать команду loadmore, а не отрабатывать события прокрутки. Я думаю, что это примерно то, что делает учебник pulltorefresh. - person Stuart; 07.04.2013
comment
Я попробую оба варианта, просто чтобы посмотреть, что выглядит чище. Спасибо за предложения. - person Vagif Abilov; 07.04.2013