#msdevcon
Community Track
Объять необъятное, или как
использовать несколько MVVM
фреймворков в одном XAML проекте
Денис Цветцих
Руководитель проектов, IceRockDev
#msdevcon
Цели
Зачем нужен
MVVM
фреймворк
Как выбрать
MVVM
фреймворк
Как
использовать
несколько
MVVM
фреймворков
Чем отличаются MVVM
фреймворки
Как выбрать MVVM
фреймворк для конкретной
платформы
Какие MVVM фреймворки
мы использовали и для
каких задач
Решение какой задачи
упрощает использование
MVVM фреймворка
4
Опрос
Кто считает, что использовать несколько
MVVM нельзя?
Кто считает, что использовать несколько
MVVM можно, но не использовал?
Кто использовал несколько MVVM в одном
проекте?
5
Зачем нужен MVVM фреймворк?
Навигация
Реализация INPC (ViewModelBase)
Команды
Message Bus (EventAggregator, Messenger)
6
Зачем нужен MVVM фреймворк?
Навигация
Реализация INPC (ViewModelBase)
Команды
Message Bus (EventAggregator, Messenger)
7
Подходы к навигации
View First
ViewModel First
Это не разные реализации паттерна MVVM,
но разные подходы к навигации с
использованием MVVM
8
ViewFirst: показать новую форму
Создать View
Создать ViewModel для View
View.DataContext = ViewModel
Инициализировать ViewModel
9
ViewFirst: показать новую форму
Navigation.Show<ViewModel>(Value);
или
Navigation.Show("View", Value);
Похоже на: http://address.ru/?arg=value
ViewFirst предлагает организовать навигацию
аналогично веб-приложению
10
ViewModelFirst: показать новую форму
Создать ViewModel
Инициализировать ViewModel
Создать View для ViewModel
View.DataContext = ViewModel
11
ViewModelFirst: показать новую форму
var vm = Navigation.Get<ViewModel>();
vm.Arg = Value;
vm.Show();
Аналогично окну WPF:
var wnd = new Window();
wnd.Arg1 = Value1;
wnd.Show();
ViewModel First навигация аналогична
навигации в настольных приложениях
12
ViewFirst vs ViewModelFirst
ViewFirst ViewModelFirst
Создать View Создать ViewModel
Создать ViewModel Инициализировать ViewModel
Инициализировать ViewModel Создать View
View.DataContext = ViewModel View.DataContext = ViewModel
13
Выбор MVVM фреймворка
Выбираем MVVM фреймворк по
реализованному подходу к навигации
Навигация MVVM фреймворка соответствует
навигации в API выбранной технологии
WPF: ViewModelFirst подход (MugenMvvmToolkit, ReactiveUI)
UWP: ViewFirst подход (Prism)
14
Какие задачи решает MVVM фреймворк?
Навигация
Команды
Привязки
На уровне ViewModel: передача событий между ViewModel
На уровне View: Binding в XAML
Разные задачи можно решать при помощи
разных фреймворков!
15
Набор MVVM фреймворков для UWP
Навигация – Prism
Собственное расширение Prism для CompositeUI
Команды – ReactiveCommand из ReactiveUI
Привязки
Привязки ViewModel: Не используем MessageBus (EventAggregator из Prism)
Привязки ViewModel: ObservableForProperty, WhenAny из ReactiveUI
Привязки View: альтернативный Binding из MugenMvvmToolkit
16
Prism - ViewFirst навигация
public interface INavigationService
{
bool Navigate(string pageToken, object param);
void GoBack();
void GoForward();
void ClearHistory();
}
17
Достоинства навигации Prism
ViewFirst подход, реализованный в Prism,
соответствует API для навигации в UWP
CompositeUI не реализован в Prism для UWP, но нужное решение есть
по ссылке
https://github.com/denis-tsv/Prism.StoreApps.Extensions.Mvvm
18
ReactiveUI: команды и ViewModel привязки
public class LoginViewModel //: INotifyPropertyChanged
{
public string Login { get; set; } // PropertyChanged
public string Password { get; set; } // PropertyChanged
public ICommand LoginCommand { get; private set; }
}
19
1. ObservableForProperty
// Подписка
IDisposable _subscription =
this.ObservableForProperty(vm => vm.Login)
.Subscribe(OnLoginChanged);
// Реакция на событие
private void OnLoginChanged
(IObservedChange<LoginViewModel, String> change)
{
}
// Отписка
_subscription.Dispose();
20
1. ObservableForProperty
// Подписка
IDisposable _subscription =
this.ObservableForProperty(vm => vm.Login)
.Subscribe(OnLoginChanged);
// Реакция на событие
private void OnLoginChanged
(IObservedChange<LoginViewModel, String> change)
{
}
// Отписка
_subscription.Dispose();
21
1. ObservableForProperty
// Подписка
IDisposable _subscription =
this.ObservableForProperty(vm => vm.Login)
.Subscribe(OnLoginChanged);
// Реакция на событие
private void OnLoginChanged
(IObservedChange<LoginViewModel, String> change)
{
}
// Отписка
_subscription.Dispose();
22
1. ObservableForProperty
// Подписка
IDisposable _subscription =
this.ObservableForProperty(vm => vm.Login)
.Subscribe(OnLoginChanged);
// Реакция на событие
private void OnLoginChanged
(IObservedChange<LoginViewModel, String> change)
{
}
// Отписка
_subscription.Dispose();
23
2. WhenAny
IDisposable _subscription =
this.WhenAny(
vm => vm.Login,
vn => vm.Password,
(login, password) =>
!string.IsNullOrEmpty(login.Value) &&
!string.IsNullOrEmpty(password.Value))
.Subscribe(OnCredentialsChanged);
24
2. WhenAny
IDisposable _subscription =
this.WhenAny(
vm => vm.Login,
vn => vm.Password,
(login, password) =>
!string.IsNullOrEmpty(login.Value) &&
!string.IsNullOrEmpty(password.Value))
.Subscribe(OnCredentialsChanged);
25
2. WhenAny
IDisposable _subscription =
this.WhenAny(
vm => vm.Login,
vn => vm.Password,
(login, password) =>
!string.IsNullOrEmpty(login.Value) &&
!string.IsNullOrEmpty(password.Value))
.Subscribe(OnCredentialsChanged);
26
Достоинства ReactiveUI привязок
Удобное решение типовых задач:
Подписка на изменение одного свойства
Подписка на изменение нескольких свойств
Уменьшается количество инфраструктурного
кода, связанного с подписками и отписками
27
ReactiveCommand
CanExecute == false, когда
Логин и пароль пустые
Выполняется запрос аутентификации на сервер
28
3. ReactiveCommand
public LoginViewModel(ILoginService loginService)
{
_loginService = loginService;
var canExecute =
this.WhenAny(vm => vm.Login, vm => vm.Password,
(login, password) =>
!string.IsNullOrEmpty(login.Value) &&
!string.IsNullOrEmpty(password.Value));
29
3. ReactiveCommand
public LoginViewModel(ILoginService loginService)
{
_loginService = loginService; // Login(login, password)
var canExecute =
this.WhenAny(vm => vm.Login, vm => vm.Password,
(login, password) =>
!string.IsNullOrEmpty(login.Value) &&
!string.IsNullOrEmpty(password.Value));
30
3. ReactiveCommand
public LoginViewModel(ILoginService loginService)
{
_loginService = loginService;
var canExecute =
this.WhenAny(vm => vm.Login, vm => vm.Password,
(login, password) =>
!string.IsNullOrEmpty(login.Value) &&
!string.IsNullOrEmpty(password.Value));
31
3. ReactiveCommand
LoginCommand = ReactiveCommand.CreateAsyncTask
(canExecute,
async _ => await _loginService.Login(Login, Password));
LoginCommand.Subscribe(OnLoginCompleted);
} // of ctor
private void OnLoginCompleted(bool loginSuccessed)
{
}
32
3. ReactiveCommand
LoginCommand = ReactiveCommand.CreateAsyncTask
(canExecute,
async _ => await _loginService.Login(Login, Password));
LoginCommand.Subscribe(OnLoginCompleted);
} // of ctor
private void OnLoginCompleted(bool loginSuccessed)
{
}
33
3. ReactiveCommand
LoginCommand = ReactiveCommand.CreateAsyncTask
(canExecute,
async _ => await _loginService.Login(Login, Password));
LoginCommand.Subscribe(OnLoginCompleted);
} // of ctor
private void OnLoginCompleted(bool loginSuccessed)
{
}
34
Достоинства ReactiveCommand
Не нужно мониторить значения свойств Login и
Password
Не нужно мониторить начало и конец
асинхронной операции логина
35
Mugen: альтернативные XAML привязки
Примеры для TextBox.Text
Text Property, Mode=TwoWay, Validate=True
Text $string.Format('{0} {1}', Prop1, Prop2), Delay=100
Text Property.MyCustomMethod()
Text Prop1 ?? Prop2
Text $CustomMethod(Prop1, Prop2, ‘string value’)
Text Prop1 == ‘test’ ? Prop2 : ‘value’
36
Достоинства XAML привязок из Mugen:
Поддержка синтаксиса C#
Операторы ??, ?:, +, -, *, /, %, , ==, !=, <, >, <=, >=, &&(and), ||(or), |, &, !,
Ключевые слова
$self – текущий элемент
$root – корневой элемент
$context – текущий DataContext
$args – текущий параметр EventArgs
37
Недостаток Mugen привязок
Альтернативная реализация Binding,
которую нужно решиться использовать в
продакшене
38
Итоги: навигация
MVVM нужен для навигации
Навигация ViewFirst
Аналог навигации в веб-приложениях
Удобна для WinRT, UWP
Реализована в Prism
Навигация ViewModelFirst
Аналог навигации в настольных приложениях
Удобна для WPF, Silverlight
Реализована в MugenMvvmToolkit, ReactiveUI
39
Несколько MVVM фреймворков для UWP
Навигация – Prism
Команды – ReactiveUI
Привязки ViewModel – ReactiveUI вместо
MessageBus (EventAggregator)
Привязки XAML – Mugen привязки вместо Binding
Prism используется как MVVM фреймворк, Mugen
и ReactiveUI – как библиотеки
40
Особенности использования нескольких MVVM
Достоинство
Соединяем преимущества всех MVVM фреймворков
Недостаток
В рамках CodeReview нужно следить за тем, что каждый MVVM
используется только для своей задачи
#msdevcon
Что дальше
Посмотреть
сэмплы
ReactiveUI и
Mugen
Начните с
небольших
задач
Выпилить
MessageBus
ReactiveUI – команды
MugenMvvmToolkit –
привязки XAML
EventAggregator или
Messenger заменить на
привязки уровня ViewModel
Вам понравится ))
#msdevcon
Полезные ресурсы
MugenMvvmToolkit
https://github.com/MugenMvvmToolkit
https://habrahabr.ru/post/236745/
ReactiveUI
http://reactiveui.net/
https://github.com/reactiveui
Как реализовать CompositeUI без MessageBus
https://github.com/denis-tsv/Prism.StoreApps.Extensions.Mvvm
#msdevcon
Q&A
Объять необъятное, или как
использовать несколько MVVM
фреймворков в одном XAML проекте
Денис Цветцих
den.tsvettsih@yandex.ru
© 2016 Microsoft Corporation. All rights reserved.

Объять необъятное, или как использовать несколько MVVM фреймворков в одном XAML проекте

  • 2.
    #msdevcon Community Track Объять необъятное,или как использовать несколько MVVM фреймворков в одном XAML проекте Денис Цветцих Руководитель проектов, IceRockDev
  • 3.
    #msdevcon Цели Зачем нужен MVVM фреймворк Как выбрать MVVM фреймворк Как использовать несколько MVVM фреймворков Чемотличаются MVVM фреймворки Как выбрать MVVM фреймворк для конкретной платформы Какие MVVM фреймворки мы использовали и для каких задач Решение какой задачи упрощает использование MVVM фреймворка
  • 4.
    4 Опрос Кто считает, чтоиспользовать несколько MVVM нельзя? Кто считает, что использовать несколько MVVM можно, но не использовал? Кто использовал несколько MVVM в одном проекте?
  • 5.
    5 Зачем нужен MVVMфреймворк? Навигация Реализация INPC (ViewModelBase) Команды Message Bus (EventAggregator, Messenger)
  • 6.
    6 Зачем нужен MVVMфреймворк? Навигация Реализация INPC (ViewModelBase) Команды Message Bus (EventAggregator, Messenger)
  • 7.
    7 Подходы к навигации ViewFirst ViewModel First Это не разные реализации паттерна MVVM, но разные подходы к навигации с использованием MVVM
  • 8.
    8 ViewFirst: показать новуюформу Создать View Создать ViewModel для View View.DataContext = ViewModel Инициализировать ViewModel
  • 9.
    9 ViewFirst: показать новуюформу Navigation.Show<ViewModel>(Value); или Navigation.Show("View", Value); Похоже на: http://address.ru/?arg=value ViewFirst предлагает организовать навигацию аналогично веб-приложению
  • 10.
    10 ViewModelFirst: показать новуюформу Создать ViewModel Инициализировать ViewModel Создать View для ViewModel View.DataContext = ViewModel
  • 11.
    11 ViewModelFirst: показать новуюформу var vm = Navigation.Get<ViewModel>(); vm.Arg = Value; vm.Show(); Аналогично окну WPF: var wnd = new Window(); wnd.Arg1 = Value1; wnd.Show(); ViewModel First навигация аналогична навигации в настольных приложениях
  • 12.
    12 ViewFirst vs ViewModelFirst ViewFirstViewModelFirst Создать View Создать ViewModel Создать ViewModel Инициализировать ViewModel Инициализировать ViewModel Создать View View.DataContext = ViewModel View.DataContext = ViewModel
  • 13.
    13 Выбор MVVM фреймворка ВыбираемMVVM фреймворк по реализованному подходу к навигации Навигация MVVM фреймворка соответствует навигации в API выбранной технологии WPF: ViewModelFirst подход (MugenMvvmToolkit, ReactiveUI) UWP: ViewFirst подход (Prism)
  • 14.
    14 Какие задачи решаетMVVM фреймворк? Навигация Команды Привязки На уровне ViewModel: передача событий между ViewModel На уровне View: Binding в XAML Разные задачи можно решать при помощи разных фреймворков!
  • 15.
    15 Набор MVVM фреймворковдля UWP Навигация – Prism Собственное расширение Prism для CompositeUI Команды – ReactiveCommand из ReactiveUI Привязки Привязки ViewModel: Не используем MessageBus (EventAggregator из Prism) Привязки ViewModel: ObservableForProperty, WhenAny из ReactiveUI Привязки View: альтернативный Binding из MugenMvvmToolkit
  • 16.
    16 Prism - ViewFirstнавигация public interface INavigationService { bool Navigate(string pageToken, object param); void GoBack(); void GoForward(); void ClearHistory(); }
  • 17.
    17 Достоинства навигации Prism ViewFirstподход, реализованный в Prism, соответствует API для навигации в UWP CompositeUI не реализован в Prism для UWP, но нужное решение есть по ссылке https://github.com/denis-tsv/Prism.StoreApps.Extensions.Mvvm
  • 18.
    18 ReactiveUI: команды иViewModel привязки public class LoginViewModel //: INotifyPropertyChanged { public string Login { get; set; } // PropertyChanged public string Password { get; set; } // PropertyChanged public ICommand LoginCommand { get; private set; } }
  • 19.
    19 1. ObservableForProperty // Подписка IDisposable_subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged); // Реакция на событие private void OnLoginChanged (IObservedChange<LoginViewModel, String> change) { } // Отписка _subscription.Dispose();
  • 20.
    20 1. ObservableForProperty // Подписка IDisposable_subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged); // Реакция на событие private void OnLoginChanged (IObservedChange<LoginViewModel, String> change) { } // Отписка _subscription.Dispose();
  • 21.
    21 1. ObservableForProperty // Подписка IDisposable_subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged); // Реакция на событие private void OnLoginChanged (IObservedChange<LoginViewModel, String> change) { } // Отписка _subscription.Dispose();
  • 22.
    22 1. ObservableForProperty // Подписка IDisposable_subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged); // Реакция на событие private void OnLoginChanged (IObservedChange<LoginViewModel, String> change) { } // Отписка _subscription.Dispose();
  • 23.
    23 2. WhenAny IDisposable _subscription= this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);
  • 24.
    24 2. WhenAny IDisposable _subscription= this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);
  • 25.
    25 2. WhenAny IDisposable _subscription= this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);
  • 26.
    26 Достоинства ReactiveUI привязок Удобноерешение типовых задач: Подписка на изменение одного свойства Подписка на изменение нескольких свойств Уменьшается количество инфраструктурного кода, связанного с подписками и отписками
  • 27.
    27 ReactiveCommand CanExecute == false,когда Логин и пароль пустые Выполняется запрос аутентификации на сервер
  • 28.
    28 3. ReactiveCommand public LoginViewModel(ILoginServiceloginService) { _loginService = loginService; var canExecute = this.WhenAny(vm => vm.Login, vm => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value));
  • 29.
    29 3. ReactiveCommand public LoginViewModel(ILoginServiceloginService) { _loginService = loginService; // Login(login, password) var canExecute = this.WhenAny(vm => vm.Login, vm => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value));
  • 30.
    30 3. ReactiveCommand public LoginViewModel(ILoginServiceloginService) { _loginService = loginService; var canExecute = this.WhenAny(vm => vm.Login, vm => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value));
  • 31.
    31 3. ReactiveCommand LoginCommand =ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password)); LoginCommand.Subscribe(OnLoginCompleted); } // of ctor private void OnLoginCompleted(bool loginSuccessed) { }
  • 32.
    32 3. ReactiveCommand LoginCommand =ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password)); LoginCommand.Subscribe(OnLoginCompleted); } // of ctor private void OnLoginCompleted(bool loginSuccessed) { }
  • 33.
    33 3. ReactiveCommand LoginCommand =ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password)); LoginCommand.Subscribe(OnLoginCompleted); } // of ctor private void OnLoginCompleted(bool loginSuccessed) { }
  • 34.
    34 Достоинства ReactiveCommand Не нужномониторить значения свойств Login и Password Не нужно мониторить начало и конец асинхронной операции логина
  • 35.
    35 Mugen: альтернативные XAMLпривязки Примеры для TextBox.Text Text Property, Mode=TwoWay, Validate=True Text $string.Format('{0} {1}', Prop1, Prop2), Delay=100 Text Property.MyCustomMethod() Text Prop1 ?? Prop2 Text $CustomMethod(Prop1, Prop2, ‘string value’) Text Prop1 == ‘test’ ? Prop2 : ‘value’
  • 36.
    36 Достоинства XAML привязокиз Mugen: Поддержка синтаксиса C# Операторы ??, ?:, +, -, *, /, %, , ==, !=, <, >, <=, >=, &&(and), ||(or), |, &, !, Ключевые слова $self – текущий элемент $root – корневой элемент $context – текущий DataContext $args – текущий параметр EventArgs
  • 37.
    37 Недостаток Mugen привязок Альтернативнаяреализация Binding, которую нужно решиться использовать в продакшене
  • 38.
    38 Итоги: навигация MVVM нужендля навигации Навигация ViewFirst Аналог навигации в веб-приложениях Удобна для WinRT, UWP Реализована в Prism Навигация ViewModelFirst Аналог навигации в настольных приложениях Удобна для WPF, Silverlight Реализована в MugenMvvmToolkit, ReactiveUI
  • 39.
    39 Несколько MVVM фреймворковдля UWP Навигация – Prism Команды – ReactiveUI Привязки ViewModel – ReactiveUI вместо MessageBus (EventAggregator) Привязки XAML – Mugen привязки вместо Binding Prism используется как MVVM фреймворк, Mugen и ReactiveUI – как библиотеки
  • 40.
    40 Особенности использования несколькихMVVM Достоинство Соединяем преимущества всех MVVM фреймворков Недостаток В рамках CodeReview нужно следить за тем, что каждый MVVM используется только для своей задачи
  • 41.
    #msdevcon Что дальше Посмотреть сэмплы ReactiveUI и Mugen Начнитес небольших задач Выпилить MessageBus ReactiveUI – команды MugenMvvmToolkit – привязки XAML EventAggregator или Messenger заменить на привязки уровня ViewModel Вам понравится ))
  • 42.
  • 43.
    #msdevcon Q&A Объять необъятное, иликак использовать несколько MVVM фреймворков в одном XAML проекте Денис Цветцих den.tsvettsih@yandex.ru
  • 44.
    © 2016 MicrosoftCorporation. All rights reserved.

Editor's Notes

  • #4 Главная мысль – использовать на одном проекте несколько Mvvm можно
  • #8 Опрос:
  • #13 Бес в деталях
  • #17 Как в браузере
  • #19 Как в браузере
  • #20 Как в браузере
  • #21 Как в браузере
  • #22 Как в браузере
  • #23 Как в браузере
  • #29 Как в браузере
  • #30 Как в браузере
  • #31 Как в браузере
  • #32 Как в браузере
  • #33 Как в браузере
  • #34 Как в браузере