Объять необъятное, или как использовать несколько MVVM фреймворков в одном XAML проекте. Денис Цветцих. Руководитель проектов, IceRockDev.


Чтобы посмотреть презентацию с картинками, оформлением и слайдами, скачайте ее файл и откройте в PowerPoint на своем компьютере.
Текстовое содержимое слайдов презентации:

Объять необъятное, или как использовать несколько MVVM фреймворков в одном XAML проектеДенис ЦветцихРуководитель проектов, IceRockDev Зачем нужен MVVM фреймворкКак выбрать MVVM фреймворкКак использовать несколько MVVM фреймворковЧем отличаются MVVM фреймворкиКак выбрать MVVM фреймворк для конкретной платформыКакие MVVM фреймворки мы использовали и для каких задачРешение какой задачи упрощает использование MVVM фреймворка



ОпросКто считает, что использовать несколько MVVM нельзя?Кто считает, что использовать несколько MVVM можно, но не использовал?Кто использовал несколько MVVM в одном проекте?

Зачем нужен MVVM фреймворк?НавигацияРеализация INPC (ViewModelBase)Команды Message Bus (EventAggregator, Messenger)

Зачем нужен MVVM фреймворк?НавигацияРеализация INPC (ViewModelBase)Команды Message Bus (EventAggregator, Messenger) Подходы к навигацииView FirstViewModel FirstЭто не разные реализации паттерна MVVM,но разные подходы к навигации с использованием MVVM

ViewFirst: показать новую формуСоздать ViewСоздать ViewModel для ViewView.DataContext = ViewModelИнициализировать ViewModel

ViewFirst: показать новую формуNavigation.Show<ViewModel>(Value);илиNavigation.Show("View", Value);Похоже на: http://address.ru/?arg=valueViewFirst предлагает организовать навигацию аналогично веб-приложению


ViewModelFirst: показать новую формуСоздать ViewModelИнициализировать ViewModelСоздать View для ViewModelView.DataContext = ViewModel

ViewModelFirst: показать новую формуvar vm = Navigation.Get<ViewModel>();vm.Arg = Value;vm.Show();Аналогично окну WPF:var wnd = new Window();wnd.Arg1 = Value1;wnd.Show();ViewModel First навигация аналогична навигации в настольных приложениях



ViewFirst vs ViewModelFirst Выбор MVVM фреймворкаВыбираем MVVM фреймворк по реализованному подходу к навигацииНавигация MVVM фреймворка соответствует навигации в API выбранной технологииWPF: ViewModelFirst подход (MugenMvvmToolkit, ReactiveUI)UWP: ViewFirst подход (Prism)

Какие задачи решает MVVM фреймворк?Навигация КомандыПривязкиНа уровне ViewModel: передача событий между ViewModelНа уровне View: Binding в XAMLРазные задачи можно решать при помощи разных фреймворков!


Набор MVVM фреймворков для UWPНавигация – PrismСобственное расширение Prism для CompositeUIКоманды – ReactiveCommand из ReactiveUIПривязкиПривязки ViewModel: Не используем MessageBus (EventAggregator из Prism)Привязки ViewModel: ObservableForProperty, WhenAny из ReactiveUIПривязки View: альтернативный Binding из MugenMvvmToolkit



Prism - ViewFirst навигацияpublic interface INavigationService{bool Navigate(string pageToken, object param);void GoBack();void GoForward();void ClearHistory();} Достоинства навигации Prism ViewFirst подход, реализованный в Prism, соответствует API для навигации в UWPCompositeUI не реализован в Prism для UWP, но нужное решение есть по ссылкеhttps://github.com/denis-tsv/Prism.StoreApps.Extensions.Mvvm

ReactiveUI: команды и ViewModel привязкиpublic class LoginViewModel //: INotifyPropertyChanged{ public string Login { get; set; } // PropertyChanged public string Password { get; set; } // PropertyChanged public ICommand LoginCommand { get; private set; }} 1. ObservableForProperty// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }// Отписка_subscription.Dispose(); 1. ObservableForProperty// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }// Отписка_subscription.Dispose(); 1. ObservableForProperty// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }// Отписка_subscription.Dispose(); 1. ObservableForProperty// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }// Отписка_subscription.Dispose(); 2. WhenAnyIDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged); 2. WhenAnyIDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged); 2. WhenAnyIDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged); Достоинства ReactiveUI привязокУдобное решение типовых задач:Подписка на изменение одного свойстваПодписка на изменение нескольких свойствУменьшается количество инфраструктурного кода, связанного с подписками и отписками

ReactiveCommandCanExecute == false, когда Логин и пароль пустыеВыполняется запрос аутентификации на сервер

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)); 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)); 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)); 3. ReactiveCommand LoginCommand = ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password)); LoginCommand.Subscribe(OnLoginCompleted);} // of ctorprivate void OnLoginCompleted(bool loginSuccessed){ } 3. ReactiveCommand LoginCommand = ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password)); LoginCommand.Subscribe(OnLoginCompleted);} // of ctorprivate void OnLoginCompleted(bool loginSuccessed){ } 3. ReactiveCommand LoginCommand = ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password)); LoginCommand.Subscribe(OnLoginCompleted);} // of ctorprivate void OnLoginCompleted(bool loginSuccessed){ } Достоинства ReactiveCommand Не нужно мониторить значения свойств Login и PasswordНе нужно мониторить начало и конец асинхронной операции логина
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’



Достоинства XAML привязок из Mugen:Поддержка синтаксиса C#Операторы ??, ?:, +, -, *, /, %, , ==, !=, <, >, <=, >=, &&(and), ||(or), |, &, !, Ключевые слова $self – текущий элемент$root – корневой элемент$context – текущий DataContext$args – текущий параметр EventArgs



Недостаток Mugen привязокАльтернативная реализация Binding, которую нужно решиться использовать в продакшене Итоги: навигацияMVVM нужен для навигацииНавигация ViewFirstАналог навигации в веб-приложенияхУдобна для WinRT, UWPРеализована в PrismНавигация ViewModelFirstАналог навигации в настольных приложенияхУдобна для WPF, SilverlightРеализована в MugenMvvmToolkit, ReactiveUI




Несколько MVVM фреймворков для UWPНавигация – PrismКоманды – ReactiveUI Привязки ViewModel – ReactiveUI вместо MessageBus (EventAggregator)Привязки XAML – Mugen привязки вместо BindingPrism используется как MVVM фреймворк, Mugen и ReactiveUI – как библиотеки


Особенности использования нескольких MVVMДостоинствоСоединяем преимущества всех MVVM фреймворковНедостатокВ рамках CodeReview нужно следить за тем, что каждый MVVM используется только для своей задачи

Посмотреть сэмплы ReactiveUI и MugenНачните с небольших задачВыпилить MessageBusReactiveUI – командыMugenMvvmToolkit – привязки XAMLEventAggregator или Messenger заменить на привязки уровня ViewModelВам понравится ))



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 Объять необъятное, или как использовать несколько MVVM фреймворков в одном XAML проектеДенис Цветцих[email protected]

Приложенные файлы

  • pptx 1240710
    Размер файла: 273 kB Загрузок: 0

Добавить комментарий