Xamarin. Как из ViewModel передавать данные в Model?

210
14 февраля 2018, 08:49

Доброе время суток. Не могу победить одну задачку:

  1. Есть Model (некий partial class, который наследует ContentPage), View и ViewModel;
  2. По нажатии на кнопку в View через Command ViewModel делает некоторые рассчеты.
  3. Рассчеты, полученные в п.2 нужно передать в новое окно (Navigation Page).

Как правильно реализовать это без применения сторонних плагинов и сохраняя концепцию MVVM чистой?

Конечно, я мог бы обойтись без ViewModel, тогда реализация довольно ясна. Но мне бы хотелось именно через MVVM. Прочитал, что вызывать алерты и окна из ViewModel не стоит, нужно передать полученные данные в Model, откуда и инициировать Navigation Page.

Я сделал это так:

  1. Передаю в ViewModel в качестве параметра конструктора экземпляр Model;
  2. В ViewModel делаю нужные рассчеты и оперирую Model, в том числе из ViewModel вызываю Model.Navigation.

Насколько такой подход корректен?

Прочитал еще, что можно из ViewModel обновлять свойства Model, и из Model реагировать на это, в т.ч. например включать триггер для открытия Navigation.

P.S. Предварительно читал эти статьи: https://msdn.microsoft.com/en-us/magazine/dd419663.aspx и https://rachel53461.wordpress.com/2011/05/08/simplemvvmexample/ Но там описывается MVVM в WPF, что немного не то, если я правильно понял, хотя и пробовал применить их.

Просьба подсказать как правильно?

PS Еще вопрос:

Я подключаю BindingContext из XAML таким образом:

<ContentPage.BindingContext>
    <ViewModels:NewsViewModel />
</ContentPage.BindingContext>

Как мне в таком случае передать в конструктор NewsViewModel объект моей модели Model?

Т.е. сделать то же самое, что в С#

NewsViewModel VM = new NewsViewModel(this);
this.BindingContext = VM;
Answer 1

Для того чтобы понять какой-либо тех.приём или применение того или иного шаблона нужно прежде всего уяснить для себя ради чего это делается, какая конечная цель преследуется.

Все эти MVC, MVP, MVVM направлены лишь на одно, на разделение ответственности, на разделение на части программного кода по функциональным обязанностям. Применительно к MVVM можно сказать следующее.

С View всё просто - это интерфейс, UI. Такое изобретение Microsoft как Dependency Property сделало возможным существование слоя ViewModel - это отделение от View всех обязанностей по непосредственной работе с данными отображающимися во View. Нужные свойства контролов из View представлены во ViewModel в виде свойств класса ViewModel, причем эти свойства "оповещают" привязанные к ним контролы об изменении своих значений с помощью вызова события PropertyChanged.

C Model всё несколько сложнее. В большинстве примеров по MVVM то, что там выдается за модель в чистом виде ей не является, а является продолжением всё той же ViewModel, так как по своей структуре и содержанию (классы со свойствами вызывающими PropertyChanged) соответствует контейнеру данных, которые отображаются во View. Для простых приложений это вполне годный вариант.

Когда же встает вопрос работы с базой данных, в особенности с реляционной СУБД, то на структуру и содержание классов модели налагаются требования обусловленные той или иной СУБД. Наиболее очевидное - это соответствие таблицы в базе данных и класса модели, т.е. класс являет собой отражение таблицы. И тут нередко возникает диссонанс между классами, с которыми работает ViewModel, и классами хранения в БД, т.е. UI отображает данные не так как они в конечном итоге хранятся в БД.

Ко всему прочему, что касается модели, следует упомянуть еще и так называемую Business Logic. В более-менее сложных программных продуктах данные не просто отображаются и изменяются пользователем, но и подразумевают над собой определенного рода вычисления, обработку по тем или иным бизнес правилам. И здесь снова возникает своя модель данных, свои классы, которые не похожи на классы хранения в БД и классы отображения в UI.

Из всего выше сказанного вы должны понять только одну мысль, что все эти шаблоны призваны лишь для одного - для правильного и логичного разделения ответственности между тем или иным классом входящим в кодовую базу приложения.

Вернемся к MVVM. Те классы, которые вы складируете в папку Models в своем проекте - это контейнеры данных вашего приложения и больше ничего. Модель ничего не знает ни о каких-либо страницах, кнопках и проч. Это просто контейнер с набором свойств, в которых хранятся данные приложения, во время его работы. Под ViewModel вы должны понимать класс, который работает с классом(ами) модели, а также с другими сервисными классами, которые могут отвечать за работу с сетью, с хранением данных и проч. Если вам необходимо из логики работы во ViewModel каким-то образом "обратиться" к пользователю программы с помощью окна запроса, переключится на др. страницу и проч. вам для этого нужно использовать в качестве посредника соответствующие классы, которые будут по запросу ViewModel обращаться к View за необходимой вам операцией, но это опять же ни в коем случае не может быть класс контейнер данных из модели.

Создайте интерфейс INavigator и объявите в нем нужные методы для переключения на нужную страницу. Далее создайте класс Navigator : INavigator реализуйте интерфейс в нем, далее в конструктор ViewModel пропишите параметр типа INavigator, потом либо с помощью какого-либо контейнера DI, либо просто руками передавайте при создании экземпляра ViewModel экземпляр Navigator. В нужном месте ViewModel вызывайте метод из INavigator. Это всё.

READ ALSO
Изменение статического свойства

Изменение статического свойства

На вопрос подтолкнули ответы из вопросаИзменения элементов статического списка и вправду подхватываются, но что насчет изменения не элемента,...

175
Unity WebGL жор памяти

Unity WebGL жор памяти

При первом запуске игры в WebGL она кушает 500 мб памяти, и в общем, меня это устраиваетНо стоит нажать F5 и загрузить игру снова, как диспетчер...

135
Unity3d GetPixels не изменяет текстуру

Unity3d GetPixels не изменяет текстуру

Имеется следующая ситуация: в Unity - у меня есть некий материал содержащий некую текстуруСтоит следующая задача: при скролинге мышью по игровому...

151