Объять необъятное, или как использовать несколько mvvm...
TRANSCRIPT
#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 FirstViewModel First
Это не разные реализации паттерна MVVM,но разные подходы к навигации с использованием MVVM
8
ViewFirst: показать новую формуСоздать ViewСоздать ViewModel для ViewView.DataContext = ViewModelИнициализировать ViewModel
9
ViewFirst: показать новую формуNavigation.Show<ViewModel>(Value);илиNavigation.Show("View", Value);
Похоже на: http://address.ru/?arg=value
ViewFirst предлагает организовать навигацию аналогично веб-приложению
10
ViewModelFirst: показать новую формуСоздать ViewModelИнициализировать ViewModelСоздать View для ViewModelView.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 ViewModelFirstViewFirst ViewModelFirstСоздать View Создать ViewModelСоздать ViewModel Инициализировать ViewModel
Инициализировать ViewModel Создать ViewView.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
Достоинства навигации PrismViewFirst подход, реализованный в Prism, соответствует API для навигации в UWPCompositeUI не реализован в 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. WhenAnyIDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);
24
2. WhenAnyIDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);
25
2. WhenAnyIDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);
26
Достоинства ReactiveUI привязокУдобное решение типовых задач:Подписка на изменение одного свойстваПодписка на изменение нескольких свойств
Уменьшается количество инфраструктурного кода, связанного с подписками и отписками
27
ReactiveCommandCanExecute == false, когда Логин и пароль пустыеВыполняется запрос аутентификации на сервер
28
3. ReactiveCommandpublic 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. ReactiveCommandpublic 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. ReactiveCommandpublic 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.TextText Property, Mode=TwoWay, Validate=TrueText $string.Format('{0} {1}', Prop1, Prop2), Delay=100Text Property.MyCustomMethod()Text Prop1 ?? Prop2Text $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 привязки вместо BindingPrism используется как MVVM фреймворк, Mugen и ReactiveUI – как библиотеки
40
Особенности использования нескольких MVVM
ДостоинствоСоединяем преимущества всех MVVM фреймворков
НедостатокВ рамках CodeReview нужно следить за тем, что каждый MVVM используется только для своей задачи
#msdevcon
Что дальше
Посмотреть сэмплы
ReactiveUI и Mugen
Начните с небольших
задачВыпилить
MessageBusReactiveUI – командыMugenMvvmToolkit –
привязки XAML
EventAggregator или Messenger заменить на
привязки уровня ViewModel
Вам понравится ))
#msdevcon
Полезные ресурсы
MugenMvvmToolkithttps://github.com/MugenMvvmToolkithttps://habrahabr.ru/post/236745/
ReactiveUIhttp://reactiveui.net/https://github.com/reactiveui
Как реализовать CompositeUI без MessageBushttps://github.com/denis-tsv/Prism.StoreApps.Extensions.Mvvm
#msdevcon
Q&AОбъять необъятное, или как использовать несколько MVVM фреймворков в одном XAML проектеДенис Цветцих[email protected]
© 2016 Microsoft Corporation. All rights reserved.