Разработка WPF приложений в стиле ViewModel FirstDenis Tsvettsih
Презентация к докладу «Разработка WPF приложений в стиле ViewModel First» с одиннадцатой конференции dotnetconf (Челябинск, 31 октября 2015)
http://dotnetconf.ru/materialy/viewmodelfirst
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)Ontico
РИТ++ 2017, AppsConf
Зал Касабланка, 6 июня, 16:00
Тезисы:
http://appsconf.ru/2017/abstracts/2704.html
В последнее время паттерн MVP будоражит Android-комьюнити. Уже есть несколько довольно приличных библиотек, которые помогают использовать этот подход. Но с ними вам придётся писать много boilerplate-кода. Поэтому я хочу познакомить вас с Moxy. Покажу, как использовать её компоненты для решения задач, которые будут вставать перед вами, когда вы решите использовать паттерн MVP. И расскажу, как устроены эти компоненты, и почему именно так, чтобы вы не боялись использовать Moxy из-за потенциальных подводных камней.
Разработка WPF приложений в стиле ViewModel FirstDenis Tsvettsih
Презентация к докладу «Разработка WPF приложений в стиле ViewModel First» с одиннадцатой конференции dotnetconf (Челябинск, 31 октября 2015)
http://dotnetconf.ru/materialy/viewmodelfirst
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)Ontico
РИТ++ 2017, AppsConf
Зал Касабланка, 6 июня, 16:00
Тезисы:
http://appsconf.ru/2017/abstracts/2704.html
В последнее время паттерн MVP будоражит Android-комьюнити. Уже есть несколько довольно приличных библиотек, которые помогают использовать этот подход. Но с ними вам придётся писать много boilerplate-кода. Поэтому я хочу познакомить вас с Moxy. Покажу, как использовать её компоненты для решения задач, которые будут вставать перед вами, когда вы решите использовать паттерн MVP. И расскажу, как устроены эти компоненты, и почему именно так, чтобы вы не боялись использовать Moxy из-за потенциальных подводных камней.
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYYMail.ru Group
Доклад о подходе к разработке Android-приложений с использованием MVP и Clean Architecture. Никита рассмотрит преимущества этого подхода перед традиционным, уделит отдельное внимание вопросам сохранения состояния в Android-MVP, а также особенностям взаимодействия между V и P.
Vue.js и его брат-близнец Vue-server.js / Андрей Солодовников (НГС)Ontico
Современный Веб всё больше стремится к динамичным, похожим на приложения, сайтам.
Оперативно строить быстрый и динамичный интерфейс на проекте N1.RU нам помогает Vue.js.
Однако, как и многие современные библиотеки и фреймворки, Vue.js не умеет рендериться на сервере.
При этом иметь такую возможность бывает полезно по нескольким причинам: начиная от вопросов SEO и заканчивая красотой загрузки страницы.
Чтобы реализовать такую возможность для Vue.js мы создали его дополнение — Vue-server.js.
Я расскажу о том, что умеет Vue.js, что у нашего дополнения "под капотом", почему мы выбрали такой путь и как, вообще, всё это работает. А ещё попробую дать критическую оценку проделанной работе.
55+1 прием для улучшения Javascript-кода / Татьяна Бабич (Simbirsoft)Ontico
В докладе будут рассмотрены приемы, практики и «фишки», которые полезно использовать для создания любого Frontend-приложения.
Мы поговорим об организации модульности и компонентов на примере приложений с Angular, React и Polymer. Обсудим, как использовать особенности JavaScript, и рассмотрим особые случаи, когда фреймворки действительно приходят на помощь.
Доклад о подходе к отслеживанию потоков данных, формирующих окружение, в котором пользователь решает свои задачи.
На примере реализации для конкретного фреймворка будет озвучена идея, как сделать инструмент для отслеживания изменений данных на странице приложения для вашего технологического стека.
Целевая аудитория
Разработчики крупных web-приложений, регулярно сталкивающиеся с проблемой, как уследить за изменением большого количества данных, формирующих интерфейс пользователя, решающих задачу эффективно разобраться с потоками данных для устранения неполадок приложения.
Человеческий организм устроен сложно. Если с ним что-то не так, то для диагностики используют магнитно-резонансный томограф.
Большие одностраничные приложения тоже устроены сложно. Чтобы их починить или обвесить новым функционалом, требуется вникнуть в их устройство. Для этого нередко приходится засучивать рукава и с головой погружаться в самую глубь проекта. И немалая часть проблем связана именно с бизнес логикой и потоками данных. Но что если у нас будет возможность проникнуть в структуру данных, способ увидеть связи между ними и отслеживать то, как они влияют друг на друга? Такой способ, чтобы не требовалось вскрытия скальпелем - все как с МРТ.
В докладе речь пойдет о собственных разработках в этой области.
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...Ontico
Совместно с университетом ИТМО мы запустили курс, посвященный основам HTML и CSS. Уже на момент регистрации на этот курс записалось более 12 тысяч студентов. Перед нами стояла задача разработать систему, которая будет автоматически проверять итоговые проекты на соответствие заранее подготовленному макету. В качестве основной техники для проверки было выбрано регрессионное тестирование.
В каждом проекте мы проверяли разметку, сетку и стилевое оформление не только страницы целиком, но и отдельных блоков. Одной из главных проблем был поиск этих самых блоков, так как о том, какой будет верстка студентов, мы не знали ничего — ни какие теги они использовали, ни какие классы и идентификаторы были задействованы. Имели только общее представление о структуре.
В докладе я расскажу, от чего мы отталкивались при построении этой системы, как мы разбирали и анализировали проекты. Какие инструменты и технологии мы для этого использовали и почему. Какие подводные камни вылезали, и какие возникали проблемы.
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)Ontico
Недавно запустили новый сайт Тинькофф.
У нас есть желание поделиться с аудиторией подходом и опытом разработки большого изоморфного приложения на React.js и Flux. Меньше чем за год мы разработали новый сайт и интернет-банк, заложив платформу на ближайшие несколько лет для быстрой разработки фронтенда новых продуктов.
Сейчас tinkoff.ru насчитывает более 3000 компонентов и сотни страниц.
Разработка Windows 8 приложений глазами WPF/Silverlight программистаDenis Tsvettsih
Презентация к докладу «Разработка Windows 8 приложений глазами WPF/Silverlight программиста» с десятой конференции dotnetconf (Челябинск, 19 апреля 2015)
http://dotnetconf.ru/materialy/windows8
Roslyn API: SyntaxTree vs CodeDom, SemanticModel vs ReflectionDenis Tsvettsih
Презентация к докладу «Roslyn API: SyntaxTree vs CodeDom, SemanticModel vs Reflection» с конференции .NEXT SPb 2015 (Санкт-Петербург, 5 июня 2015)
http://spb2015.dotnext.ru/#cvetkih_talk
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYYMail.ru Group
Доклад о подходе к разработке Android-приложений с использованием MVP и Clean Architecture. Никита рассмотрит преимущества этого подхода перед традиционным, уделит отдельное внимание вопросам сохранения состояния в Android-MVP, а также особенностям взаимодействия между V и P.
Vue.js и его брат-близнец Vue-server.js / Андрей Солодовников (НГС)Ontico
Современный Веб всё больше стремится к динамичным, похожим на приложения, сайтам.
Оперативно строить быстрый и динамичный интерфейс на проекте N1.RU нам помогает Vue.js.
Однако, как и многие современные библиотеки и фреймворки, Vue.js не умеет рендериться на сервере.
При этом иметь такую возможность бывает полезно по нескольким причинам: начиная от вопросов SEO и заканчивая красотой загрузки страницы.
Чтобы реализовать такую возможность для Vue.js мы создали его дополнение — Vue-server.js.
Я расскажу о том, что умеет Vue.js, что у нашего дополнения "под капотом", почему мы выбрали такой путь и как, вообще, всё это работает. А ещё попробую дать критическую оценку проделанной работе.
55+1 прием для улучшения Javascript-кода / Татьяна Бабич (Simbirsoft)Ontico
В докладе будут рассмотрены приемы, практики и «фишки», которые полезно использовать для создания любого Frontend-приложения.
Мы поговорим об организации модульности и компонентов на примере приложений с Angular, React и Polymer. Обсудим, как использовать особенности JavaScript, и рассмотрим особые случаи, когда фреймворки действительно приходят на помощь.
Доклад о подходе к отслеживанию потоков данных, формирующих окружение, в котором пользователь решает свои задачи.
На примере реализации для конкретного фреймворка будет озвучена идея, как сделать инструмент для отслеживания изменений данных на странице приложения для вашего технологического стека.
Целевая аудитория
Разработчики крупных web-приложений, регулярно сталкивающиеся с проблемой, как уследить за изменением большого количества данных, формирующих интерфейс пользователя, решающих задачу эффективно разобраться с потоками данных для устранения неполадок приложения.
Человеческий организм устроен сложно. Если с ним что-то не так, то для диагностики используют магнитно-резонансный томограф.
Большие одностраничные приложения тоже устроены сложно. Чтобы их починить или обвесить новым функционалом, требуется вникнуть в их устройство. Для этого нередко приходится засучивать рукава и с головой погружаться в самую глубь проекта. И немалая часть проблем связана именно с бизнес логикой и потоками данных. Но что если у нас будет возможность проникнуть в структуру данных, способ увидеть связи между ними и отслеживать то, как они влияют друг на друга? Такой способ, чтобы не требовалось вскрытия скальпелем - все как с МРТ.
В докладе речь пойдет о собственных разработках в этой области.
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...Ontico
Совместно с университетом ИТМО мы запустили курс, посвященный основам HTML и CSS. Уже на момент регистрации на этот курс записалось более 12 тысяч студентов. Перед нами стояла задача разработать систему, которая будет автоматически проверять итоговые проекты на соответствие заранее подготовленному макету. В качестве основной техники для проверки было выбрано регрессионное тестирование.
В каждом проекте мы проверяли разметку, сетку и стилевое оформление не только страницы целиком, но и отдельных блоков. Одной из главных проблем был поиск этих самых блоков, так как о том, какой будет верстка студентов, мы не знали ничего — ни какие теги они использовали, ни какие классы и идентификаторы были задействованы. Имели только общее представление о структуре.
В докладе я расскажу, от чего мы отталкивались при построении этой системы, как мы разбирали и анализировали проекты. Какие инструменты и технологии мы для этого использовали и почему. Какие подводные камни вылезали, и какие возникали проблемы.
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)Ontico
Недавно запустили новый сайт Тинькофф.
У нас есть желание поделиться с аудиторией подходом и опытом разработки большого изоморфного приложения на React.js и Flux. Меньше чем за год мы разработали новый сайт и интернет-банк, заложив платформу на ближайшие несколько лет для быстрой разработки фронтенда новых продуктов.
Сейчас tinkoff.ru насчитывает более 3000 компонентов и сотни страниц.
Разработка Windows 8 приложений глазами WPF/Silverlight программистаDenis Tsvettsih
Презентация к докладу «Разработка Windows 8 приложений глазами WPF/Silverlight программиста» с десятой конференции dotnetconf (Челябинск, 19 апреля 2015)
http://dotnetconf.ru/materialy/windows8
Roslyn API: SyntaxTree vs CodeDom, SemanticModel vs ReflectionDenis Tsvettsih
Презентация к докладу «Roslyn API: SyntaxTree vs CodeDom, SemanticModel vs Reflection» с конференции .NEXT SPb 2015 (Санкт-Петербург, 5 июня 2015)
http://spb2015.dotnext.ru/#cvetkih_talk
The difference between the Small Business Owner Mindset and the Entrepreneuri...jane GARDNER
Many small businesses operate under an employee mindset. If your goal as a small business owner is to grow, you need to think like an entrepreneur.A Entrepreneur has big ideas
SBOs solve local problems. They know their business and target audience.To develop your success mindset
go to http://jgtips.com/smindset.
A thought-starter deck on why and how to plan a truly best-practice digital content marketing strategy for B2B companies across Asia and the world. A planning perspective from Zaheer Nooruddin, Head of Digital Innovation, Asia, at Integrated Creative Communications agency, GOLIN.
Сегодня многие фреймворки, такие как Prism или Autofac, позволяют разработчику организовать модульную структуру приложения. При этом часто бывает непонятно, для чего ещё нужны модули, кроме как для пресловутой "красоты архитектуры".
В рамках доклада я расскажу о том, какие существуют подходы к организации модульной структуры, в каких фреймворках они реализованы и для решения каких задач дает преимущество каждый подход.
JavaScript-модули "из прошлого в будущее"oelifantiev
Доклад на первом Ярославском форнтэнд-митапе.
Рассказ об имеющихся методиках описания модулей в JavaScript а также о грядущем стандарте ES6 и, наконец-то, нативной поддержке модулей языком.
Михаил Давыдов "Масштабируемые JavaScript-приложения"Yandex
Михаил Давыдов "Масштабируемые JavaScript-приложения"
Я.Субботник в Челябинске в рамках конференции UWDC
О докладе:
О чем нужно подумать во время проектирования архитектуры. Какую архитектуру нужно заложить, чтобы приложение могло безболезненно развиваться.
Разработка Web-приложений на Angular JS. Архитектурные семинары SoftengiSoftengi
Разработка Web-приложений на Angular JS — доклад Бориса Левицкого, архитектора ПО в команде портфеля проектов Enviance компании Softengi.
Видео с докладом от автора можно посмотреть по ссылке: http://youtu.be/oTXxrmIxo8Y
Презентация ответит на вопросы:
- что такое Angular?
- для чего он используется и что с ним можно делать?
- как работает Data-Binding?
- кастомные фильтры
- структура Angular приложения
Архитектурные семинары Softengi - еженедельные встречи, на которые приглашаются ведущие разработчики/архитекторы Softengi и других компаний нашего консорциума Intecracy Group.
Все проведенные семинары мы записывали, и теперь хотим поделиться опытом и знаниями с такими же профессионалами.
Подписывайся на канал Softengi https://www.youtube.com/user/softengi и узнай первым о новых семинарах.
http://www.softengi.com
Михаил Давыдов "Масштабируемые JavaScript-приложения"Yandex
2 июля 2011, Я.Субботник в Екатеринбурге
Михаил Давыдов "Масштабируемые JavaScript-приложения"
О докладе:
Проектирование масштабируемых JavaScript-приложений уровня Яндекс.Почты.
Чем отличается сайт от JavaScript приложения? Какие проблемы могут возникнуть при разработке многокомпонентных приложений? Какую архитектуру нужно заложить, чтобы приложение могло легко развиваться?
Вопросы, возникающие при использовании MVC, и их решение при помощи VIPER.
1. Проблемы, решаемые VIPER-ом. История появления.
2. Структура VIPER-модуля
3. Сервисы
4. Data flow
5. Навигация
6. Вложенные модули
7. Data flow между модулями
8. Кодогенерация. Vipergen
Архитектура кода нового 2ГИС Web API или куда мы дели MVCDevDay
Сергей Коржнев
Архитектор версии 1.4 2ГИС Web API
Архитектура кода нового 2ГИС Web API или куда мы дели MVC
Тезисы:
● Как организован код в старой версии.
● Вдумчиво смотрим, как мы используем Yii, хватаемся за голову и клавиатуру. Там отрезаем, тут пришиваем, и вуаля!
● Ну и делаем выводы, как мы забороли две классические проблемы программирования: борьба с дублированием кода и сложностью системы.
1. Как разрабатывать UI XAML приложений
(Prism) и веб-приложений (Angular2,
React) без Message Bus
Денис Цветцих
One Systems
DotNext Msk
9 декабря 2016
http://dotnext-moscow.ru/
2. 2
Message Bus – паттерн для интеграции
MessageBus
Application 1 Application 2
Application 3 Application 4
3. 3
Чем плох MessageBus на UI
• Взаимодействие объектов неявное
• Сложно дебажить
• В больших проектах MessageHell
• Простор для костылей
• Messages вместо Events
• Messages вместо Bindings
5. 5
Виноват Composite Application Blocks
public class MasterController : Controller
{
[EventPublication("GlobalEvent")]
public event EventHandler GlobalEvent;
}
public class DetailController : Controller
{
[EventSubscription("GlobalEvent")]
public void OnGlobalEvent(object sender, EventArgs e)
{
}
}
6. 6
Виноват Composite Application Blocks
public class MasterController : Controller
{
[EventPublication("GlobalEvent")]
public event EventHandler GlobalEvent;
}
public class DetailController : Controller
{
[EventSubscription("GlobalEvent")]
public void OnGlobalEvent(object sender, EventArgs e)
{
}
}
7. 7
Виноват Composite Application Blocks
public class MasterController : Controller
{
[EventPublication("GlobalEvent")]
public event EventHandler GlobalEvent;
}
public class DetailController : Controller
{
[EventSubscription("GlobalEvent")]
public void OnGlobalEvent(object sender, EventArgs e)
{
}
}
8. 8
Виноват Composite Application Blocks
public class MasterController : Controller
{
[EventPublication("GlobalEvent")]
public event EventHandler GlobalEvent;
}
public class DetailController : Controller
{
[EventSubscription("GlobalEvent")]
public void OnGlobalEvent(object sender, EventArgs e)
{
}
}
9. 9
Виноват Composite Application Blocks
public class MasterController : Controller
{
[EventPublication("GlobalEvent")]
public event EventHandler GlobalEvent;
}
public class DetailController : Controller
{
[EventSubscription("GlobalEvent")]
public void OnGlobalEvent(object sender, EventArgs e)
{
}
}
10. 10
Виноват Composite Application Blocks
public class MasterController : Controller
{
[EventPublication("GlobalEvent")]
public event EventHandler GlobalEvent;
}
public class DetailController : Controller
{
[EventSubscription("GlobalEvent")]
public void OnGlobalEvent(object sender, EventArgs e)
{
}
}
11. 11
Виноват Composite Application Blocks
public class MasterController : Controller
{
[EventPublication("GlobalEvent")]
public event EventHandler GlobalEvent;
}
public class DetailController : Controller
{
[EventSubscription("GlobalEvent")]
public void OnGlobalEvent(object sender, EventArgs e)
{
}
}
12. 12
CAB UI: скрытая угроза
• Нет класса EventAggregator
• Но
• Любой контроллер может подписаться на
• Любое событие
• Любого другого контроллера
• Неявно (при помощи атрибута)
13. 13
Message Bus есть во всех MVVM
• Prism – по инерции от Composite App Blocks
• Caliburn.Micro – для поддержки View-First и ViewModel-First
• MVVM от энтузиастов
• Не знают как по-другому
• Делают как у всех
14. 14
О чем мы поговорим?
• Типовые UI-задачи для MessageBus
• UI Composition
• Смена контекста
• Костыли
• Как без него обойтись
• MVVM-фреймворки для WPF и UWP без MessageBus
• Что c MessageBus на JS (Angular2, React)
15. 15
Опрос
• Кто использовал MessageBus на UI?
• И считает что без него обойтись нельзя
• И считает, что без него использовать можно
• Кто не использовал MessageBus на UI?
16. 16
Примеры с INPC кодом
public class DetailViewModel : BindableBase
{
public User User
{
get { return _user; }
set { SetProperty(ref _user, value); }
}
}
24. 24
View-First: по вьюхе создаем ViewModel
public partial class MasterView
{
[Import]
public MasterViewModel ViewModel
{
set { DataContext = value; }
}
}
27. 27
MasterViewModel
public class MasterViewModel
{
public User SelectedUser
{
get { return _selectedUser; }
set
{
SetProperty(ref _selectedUser, value);
EventAggregator.GetEvent<UserChangedMessage>()
.Publish(_selectedUser);
}
}
public ObservableCollection<User> Users { get; set; }
}
28. 28
MasterViewModel
public class MasterViewModel
{
public User SelectedUser
{
get { return _selectedUser; }
set
{
SetProperty(ref _selectedUser, value);
EventAggregator.GetEvent<UserChangedMessage>()
.Publish(_selectedUser);
}
}
public ObservableCollection<User> Users { get; set; }
}
29. 29
MasterViewModel
public class MasterViewModel
{
public User SelectedUser
{
get { return _selectedUser; }
set
{
SetProperty(ref _selectedUser, value);
EventAggregator.GetEvent<UserChangedMessage>()
.Publish(_selectedUser);
}
}
public ObservableCollection<User> Users { get; set; }
}
30. 30
MasterViewModel
public class MasterViewModel
{
public User SelectedUser
{
get { return _selectedUser; }
set
{
SetProperty(ref _selectedUser, value);
EventAggregator.GetEvent<UserChangedMessage>()
.Publish(_selectedUser);
}
}
public ObservableCollection<User> Users { get; set; }
}
31. 31
DetailViewModel
public class DetailViewModel : BindableBase
{
public DetailViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<UserChangedMessage>()
.Subscribe(OnUserChanged);
}
public User User { get; set; }
public void OnUserChanged(User user)
{
User = user;
}
}
32. 32
DetailViewModel
public class DetailViewModel : BindableBase
{
public DetailViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<UserChangedMessage>()
.Subscribe(OnUserChanged);
}
public User User { get; set; }
public void OnUserChanged(User user)
{
User = user;
}
}
33. 33
DetailViewModel
public class DetailViewModel : BindableBase
{
public DetailViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<UserChangedMessage>()
.Subscribe(OnUserChanged);
}
public User User { get; set; }
public void OnUserChanged(User user)
{
User = user;
}
}
34. 34
DetailViewModel
public class DetailViewModel : BindableBase
{
public DetailViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<UserChangedMessage>()
.Subscribe(OnUserChanged);
}
public User User { get; set; }
public void OnUserChanged(User user)
{
User = user;
}
}
35. 35
DetailViewModel
public class DetailViewModel : BindableBase
{
public DetailViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<UserChangedMessage>()
.Subscribe(OnUserChanged);
}
public User User { get; set; }
public void OnUserChanged(User user)
{
User = user;
}
}
36. 36
Это работает, но …
Чем плохо:
• Для UserChangedMessage только один получатель
• MessageBus – из пушки по воробьям
• Но без него никак
Чего хочется:
• Биндинг MasterVM.SelectedUser на DetailVM.User
47. 47
Подвох от Prism
Prism предлагает RegionManager (ViewFirt) для:
• View-Switching Navigation
• UI Composition
48. 48
Что делать?
• Разделить задачи ViewSwitching Navigation и UI Composition
• RegionManager – только для навигации
• Не использовать RegionManager для UI Composition
49. 49
UI Composition vs View-Switching Navigation
UI Composition View-Switching Navigation
Делим форму на части Да Да
Зачем делим Части проще и повторно
используются
Меняем регионы
на рантайме
Нет
Выделяем
статическую часть (меню) и
динамическую (регион)
Да
Нельзя (менять
подход к навигации)
Можно (скрепя сердце)Не использовать
MessageBus
52. 52
MasterDetailViewModel
public class MasterDetailViewModel
{
public MasterViewModel MasterViewModel { get; }
public DetailViewModel DetailViewModel { get; }
public MasterDetailViewModel()
{
MasterViewModel
.WhenAny(m => m.SelectedUser, user => user.Value)
.BindTo(DetailViewModel, d => d.User);
}
}
55. 55
View-Switching в разных MVVM
ViewModel-First (можно использовать для UI Composition)
• Caliburn.Micro
• MugenMvvmToolkit
View-First (нельзя использовать для UI Composition)
• Prism.WPF
• ReactiveUI (UI Composition сделать сложно)
56. 56
Не умеют View-Switching
• Prism.Windows (UWP)
• MvvmLight
• MvvmCross
• ReactiveUI (умеет, UI Composition сделать сложно)
72. 72
View-Switching
• Отдельная задача от Navigation
• Табы
• MDI
• Отдельная задача от UI Composition
• UI Composition не требует менять UI на рантайме
73. 73
UI Composition без MessageBus
• Разделить задачи View-Switching Navigation и UI Composition
• Не использовать ViewSwitching View-First для UI Composition
• RegionManager из Prism
• Можно использовать ViewSwitching ViewModel-First для UI Composition
• Caliburn.Micro
• MugenMvvmToolkit
• UI Composition без ViewSwitching (ViewModel в DataContext для View)
• MVVM без View-Switching (Prism.Windows)
• Если нужен ViewSwitching для UI Composition
• Отдельный View-ViewModel маппинг
• ViewModelPresenter
84. 84
Обычные события вместо широковещательных
public class ApplicationStateManager
{
public event EventHandler<ApplicationStateChangedEventArgs> ApplicationStateChanged;
public ApplicationState ApplicationState
{
get { return _applicationState; }
set
{
var oldValue = _applicationState;
_applicationState = value;
OnApplicationStateChanged(oldValue, _applicationState);
}
}
}
85. 85
Обычные события вместо широковещательных
public class ApplicationStateManager
{
public event EventHandler<ApplicationStateChangedEventArgs> ApplicationStateChanged;
public ApplicationState ApplicationState
{
get { return _applicationState; }
set
{
var oldValue = _applicationState;
_applicationState = value;
OnApplicationStateChanged(oldValue, _applicationState);
}
}
}
86. 86
Обычные события вместо широковещательных
public class ApplicationStateManager
{
public event EventHandler<ApplicationStateChangedEventArgs> ApplicationStateChanged;
public ApplicationState ApplicationState
{
get { return _applicationState; }
set
{
var oldValue = _applicationState;
_applicationState = value;
OnApplicationStateChanged(oldValue, _applicationState);
}
}
}
87. 87
Обычные события вместо широковещательных
public class ApplicationStateManager
{
public event EventHandler<ApplicationStateChangedEventArgs> ApplicationStateChanged;
public ApplicationState ApplicationState
{
get { return _applicationState; }
set
{
var oldValue = _applicationState;
_applicationState = value;
OnApplicationStateChanged(oldValue, _applicationState);
}
}
}
88. 88
ApplicationStateManager vs MessageBus
Частных решений не будет много (у нас - одно)
ApplicationStateManager MessageBus
Подписчик Любой Любой
Отправитель ApplicationStateManager Любой
Событие ApplicationStateChanged Любое
90. 90
Пример цепочки вызовов методов
Package Prism.Windows
Класс PrismApplication.cs
Метод OnSuspending
https://github.com/PrismLibrary/Prism/blob/master/Source/Windows10/Prism.Windows/PrismApplication.cs
91. 91
Цепочка вызовов vs частное решение
Цепочка вызовов
+ Не требует генерации событий
- Нужна продуманная архитектура
Частное решение
+ Их не будет много
- Хочется заменить частное на универсальное (MessageBus)
95. 95
DetailViewModel
public class DetailViewModel : IHandle<UserChangedMessage>
{
public User User { get; set; }
public void Handle(UserChangedMessage message)
{
User = message.User;
if (User?.IsNew)
{
EventAggregator.PublishOnUIThread(new FocusMessage());
}
}
}
96. 96
DetailViewModel
public class DetailViewModel : IHandle<UserChangedMessage>
{
public User User { get; set; }
public void Handle(UserChangedMessage message)
{
User = message.User;
if (User?.IsNew)
{
EventAggregator.PublishOnUIThread(new FocusMessage());
}
}
}
97. 97
DetailViewModel
public class DetailViewModel : IHandle<UserChangedMessage>
{
public User User { get; set; }
public void Handle(UserChangedMessage message)
{
User = message.User;
if (User?.IsNew)
{
EventAggregator.PublishOnUIThread(new FocusMessage());
}
}
}
98. 98
DetailView
public partial class DetailView : UserControl, IHandle<FocusMessage>
{
public void Handle(FocusMessage message)
{
FirstNameTextBox.Focus();
}
}
99. 99
DetailView
public partial class DetailView : UserControl, IHandle<FocusMessage>
{
public void Handle(FocusMessage message)
{
FirstNameTextBox.Focus();
}
}
100. 100
Как обойтись – Behavior (или Trigger)
public class FocusNewUserBehavior : Behavior<TextBox>
{
public static readonly DependencyProperty User /* код опущен */
private static void OnUserChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (FocusNewUserBehavior) d;
if (behavior.User?.IsNew)
{
behavior.AssociatedObject.Focus();
}
}
}
101. 101
Как обойтись – Behavior (или Trigger)
public class FocusNewUserBehavior : Behavior<TextBox>
{
public static readonly DependencyProperty User /* код опущен */
private static void OnUserChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (FocusNewUserBehavior) d;
if (behavior.User?.IsNew)
{
behavior.AssociatedObject.Focus();
}
}
}
102. 102
Как обойтись – Behavior (или Trigger)
public class FocusNewUserBehavior : Behavior<TextBox>
{
public static readonly DependencyProperty User /* код опущен */
private static void OnUserChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (FocusNewUserBehavior) d;
if (behavior.User?.IsNew)
{
behavior.AssociatedObject.Focus();
}
}
}
103. 103
Как обойтись – Behavior (или Trigger)
public class FocusNewUserBehavior : Behavior<TextBox>
{
public static readonly DependencyProperty User /* код опущен */
private static void OnUserChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (FocusNewUserBehavior) d;
if (behavior.User?.IsNew)
{
behavior.AssociatedObject.Focus();
}
}
}
104. 104
Как обойтись – Behavior (или Trigger)
public class FocusNewUserBehavior : Behavior<TextBox>
{
public static readonly DependencyProperty User /* код опущен */
private static void OnUserChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (FocusNewUserBehavior) d;
if (behavior.User?.IsNew)
{
behavior.AssociatedObject.Focus();
}
}
}
105. 105
Как обойтись – Behavior (или Trigger)
public class FocusNewUserBehavior : Behavior<TextBox>
{
public static readonly DependencyProperty User /* код опущен */
private static void OnUserChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (FocusNewUserBehavior) d;
if (behavior.User?.IsNew)
{
behavior.AssociatedObject.Focus();
}
}
}
109. 109
Не Observable модели (Prism)
protected void UpdatePrice(string tickerSymbol, decimal newPrice)
{
_priceList[tickerSymbol] = newPrice;
OnPricesUpdated();
}
private void OnPricesUpdated()
{
var clonedPriceList = new Dictionary<string, decimal>(_priceList);
EventAggregator.GetEvent<MarketPricesUpdatedEvent>().Publish(clonedPriceList);
}
110. 110
Не Observable модели (Prism)
protected void UpdatePrice(string tickerSymbol, decimal newPrice)
{
_priceList[tickerSymbol] = newPrice;
OnPricesUpdated();
}
private void OnPricesUpdated()
{
var clonedPriceList = new Dictionary<string, decimal>(_priceList);
EventAggregator.GetEvent<MarketPricesUpdatedEvent>().Publish(clonedPriceList);
}
111. 111
Не Observable модели (Prism)
protected void UpdatePrice(string tickerSymbol, decimal newPrice)
{
_priceList[tickerSymbol] = newPrice;
OnPricesUpdated();
}
private void OnPricesUpdated()
{
var clonedPriceList = new Dictionary<string, decimal>(_priceList);
EventAggregator.GetEvent<MarketPricesUpdatedEvent>().Publish(clonedPriceList);
}
112. 112
Не Observable модели (Prism)
protected void UpdatePrice(string tickerSymbol, decimal newPrice)
{
_priceList[tickerSymbol] = newPrice;
OnPricesUpdated();
}
private void OnPricesUpdated()
{
var clonedPriceList = new Dictionary<string, decimal>(_priceList);
EventAggregator.GetEvent<MarketPricesUpdatedEvent>().Publish(clonedPriceList);
}
113. 113
Не Observable модели (Prism)
protected void UpdatePrice(string tickerSymbol, decimal newPrice)
{
_priceList[tickerSymbol] = newPrice;
OnPricesUpdated();
}
private void OnPricesUpdated()
{
var clonedPriceList = new Dictionary<string, decimal>(_priceList);
EventAggregator.GetEvent<MarketPricesUpdatedEvent>().Publish(clonedPriceList);
}
114. 114
Не Observable модели (Prism)
protected void UpdatePrice(string tickerSymbol, decimal newPrice)
{
_priceList[tickerSymbol] = newPrice;
OnPricesUpdated();
}
private void OnPricesUpdated()
{
var clonedPriceList = new Dictionary<string, decimal>(_priceList);
EventAggregator.GetEvent<MarketPricesUpdatedEvent>().Publish(clonedPriceList);
}
115. 115
Не Observable модели (Prism)
protected void UpdatePrice(string tickerSymbol, decimal newPrice)
{
_priceList[tickerSymbol] = newPrice;
OnPricesUpdated();
}
private void OnPricesUpdated()
{
var clonedPriceList = new Dictionary<string, decimal>(_priceList);
EventAggregator.GetEvent<MarketPricesUpdatedEvent>().Publish(clonedPriceList);
}
116. 116
Решение – Observable модель
public class ObservableDictionary<TKey, TValue>:
INotifyCollectionChanged,
INotifyPropertyChanged
{
}
https://code.msdn.microsoft.com/windowsdesktop/Samples-for-Parallel-b4b76364
117. 117
Не Observable модели (Prism)
protected void UpdatePrice(string tickerSymbol, decimal newPrice)
{
_priceList[tickerSymbol] = newPrice;
OnPricesUpdated();
}
private void OnPricesUpdated()
{
var clonedPriceList = new Dictionary<string, decimal>(_priceList);
EventAggregator.GetEvent<MarketPricesUpdatedEvent>().Publish(clonedPriceList);
}
118. 118
Observable модель
protected void UpdatePrice(string tickerSymbol, decimal newPrice)
{
_priceList[tickerSymbol] = newPrice;
OnPricesUpdated();
}
private void OnPricesUpdated()
{
var clonedPriceList = new Dictionary<string, decimal>(_priceList);
EventAggregator.GetEvent<MarketPricesUpdatedEvent>().Publish(clonedPriceList);
}
120. 120
MVVM фреймворки без MessageBus
• Таких нет
• В отдельном пакете
• Prism 5 – SubEvents (в Prism 6 уже неотделяем)
• MvvmCross – Messenger plugin
122. 122
Как жить без MessageBus на WPF и UWP
• Caliburn.Micro
• MugenMvvmToolkit
• MVVM без UI Composition
• + свой ViewModel-First UI Composition
123. 123
Не позволяет жить без MessageBus
WPF
• Prism.WPF
UWP
• Таких нет
• Prism.Windows без UI Composition
Как добавить UI Composition: https://github.com/denis-tsv/Prism.StoreApps.Extensions.Mvvm
124. 124
MessageBus на UI
Для чего используется Как обойтись
UI Composition Разделение UI Composition и ViewSwitching
Глобальные события
(смена контекста или lifecycle)
Цепочка вызовов методов
Частные решения с обычными событиями
ViewModel-View Message Triggers, Behaviors
Logic-ViewModel Message Observable Model
Избежать Messages между уровнями Разные сборки для View, ViewModel, Logic
Messages в сборке ViewModel
125. 125
Главная проблема MessageBus на UI – костыли!
Messages между слоями
• Messages вместо Events (Logic -> ViewModel Messages)
• Messages вместо Bindings (ViewModel -> View Messages)
126. 126
Как можно жить с MessageBus на UI
• UI Composition в стиле View-First (Prism.WPF)
• Отдельные сборки View, ViewModel, Logic
• Messages только в ViewModel
• Глобальные Messages
127. 127
Моя позиция
• Большинство бизнес-приложений маленькие и средние
• Команда 3-7 человек
• Срок пара месяцев – пара лет
• UI сложнее бэкэнда
• Не нужно CQRS, Microservices, DataAccess Abstraction
• MessageBus
• Ещё сильнее запутывает и так сложный UI
• Любую UI задачу можно решить без MessageBus
• Примеры Prism без EventAggregator полезная ссылка №2
• Строка «MessageBus» ломает билд полезная ссылка №9
128. 128
Paul Betts (ReactiveUI author) about MessageBus
… there are often
more correct ways
to solve problems,
given a bit of
ingenuity …
129. 129
В параллельной вселенной JS
Сходства
• Fontend не уступает Backend по сложности
• Развесистые JS-фреймворки (Angular, React)
• Компонент JS = Регион XAML
• Компонент (Шаблон + Поведение)
• Регион (View + ViewModel)
130. 130
Olical EventEmitter
var ee = new EventEmitter();
function listener() { }
ee.addListener('event', listener);
ee.emitEvent('event');
ee.removeListener('event', listener);
131. 131
Olical EventEmitter
var ee = new EventEmitter();
function listener() { }
ee.addListener('event', listener);
ee.emitEvent('event');
ee.removeListener('event', listener);
132. 132
Olical EventEmitter
var ee = new EventEmitter();
function listener() { }
ee.addListener('event', listener);
ee.emitEvent('event');
ee.removeListener('event', listener);
133. 133
Angular2 EventEmitter – Observer, а не MessageBus
class EventEmitter {
constructor(isAsync?: boolean)
emit(value?: T)
subscribe(generatorOrNext?: any, error?: any, complete?: any)
: any
}
134. 134
Angular2 EventEmitter – Observer, а не MessageBus
class EventEmitter {
constructor(isAsync?: boolean)
emit(value?: T)
subscribe(generatorOrNext?: any, error?: any, complete?: any)
: any
}
135. 135
Angular2 EventEmitter – Observer, а не MessageBus
class EventEmitter {
constructor(isAsync?: boolean)
emit(value?: T)
subscribe(generatorOrNext?: any, error?: any, complete?: any)
: any
}
136. 136
Angular2 EventEmitter – Observer, а не MessageBus
class EventEmitter {
constructor(isAsync?: boolean)
emit(value?: T)
subscribe(generatorOrNext?: any, error?: any, complete?: any)
: any
}
167. 167
React Context – не MessageBus
Задача
• Передача от родителя к вложенным компонентам
• С уровня 1 на уровень 3 минуя уровень 2
Особенности реализации
• Доступен родительскому и вложенным компонентам (не любым
компонентам)
• Обновление контекста во вложенных компонентах не работает
Это не MessageBus
168. 168
Резюме: MessageBus на JS
• MessageBus существует, но в виде отдельных библиотек
• MessageBus нет в коробке флагманов Angular2 и React
• Официальный гайд не рекомендует MesageBus
• Компонент != ViewModel
• Компонент = Шаблон + Поведение
• ViewModel = Поведение
• На JS нет разных видов композиции ViewFirst и ViewModelFirst
• Для JS MessageBus не является проблемой, как в XAML
• Продуманная архитектура JS фреймворков – аргумент за
переписывание UI на web-стек
169. 169
Полезные ссылки
1. MessageBus, врага нужно знать в лицо
https://msdn.microsoft.com/en-us/library/ff647328.aspx
2. Примеры StockTrader и UIComposition для Prism.WPF, откуда выпилен EventAggregator
https://github.com/denis-tsv/Prism-Samples-Wpf-NoEventAggregetor
3. Как добавить UI Composition для Prism.Windows (UWP)
https://github.com/denis-tsv/Prism.StoreApps.Extensions.Mvvm
4. Paul Betts. MessageBus and why you shouldn't use it
http://log.paulbetts.org/messagebus-and-why-you-shouldnt-use-it/
5, Caliburn.Micro Классный, минималистичный, кроссплатформенный и мультипарадигменный MVVM, в котором нет ничего лишнего
http://caliburnmicro.com/
6. MugenMvvmToolkit. Мощный UI фреймворк с офигительными кастомными XAML биндингами
https://github.com/MugenMvvmToolkit
https://habrahabr.ru/post/236745/
7. ReactiveUI. Биндинг свойств одной ViewModel на свойства другой ViewModel в родительской ViewModel
http://reactiveui.net/
8. Пример View-ViewModel mapping с использованием MEF
http://www.intuit.ru/EDI/14_12_14_2/1418505481-18353/tutorial/1050/objects/1/files/SampleSolution.zip
9. Как сломать билд (о, да!) словом MessageBus, EventAggregator, Messenger и любой другой реализацией MessageBus
http://hmemcpy.com/2013/03/even-more-resharper-annotations-hackery-marking-3rd-party-code-as-obsolete/
Паттерн, предназначенный для обмена сообщениями между процессами (бэкэнд)
Про него много говорят в области микросервисов
MessageBus позволяет любому процессу отправить сообщение любому другому процессу
Кто виноват и что делать?
Кто по картинке узнал виновника?
Как и при авиакатастрофах все списывают на мертвых
Нет явной подписки, она в инфраструктуре CAB UI
Мышки кололись и плакали но продолжали есть кактус
UI Composition – это разделение больших и сложных форм на более просты составляющие и настройка взаимодействия между ними.
Маленькие части проще писать и их можно повторно использовать
MessageBus – для настройки взаимодействия между формами
Содержимое правого региона меняется на рантайме
Только делим форму на части, на рантайме не меняем содержимое региона
Нет родительской ViewModel
Messages между ViewModel регионов
Родительская ViewModel
Взаимодействие ViewModel регионов в родительской ViewModel
Более продвинутое решение для View-Switching Navigation используется для более простой задачи UI Composition
Далее цепочка
View-Switching Navigation (View-First) для UI Composition
Message Bus для передачи сообщений между ViewModel
View-Switching Navigation и UI Composition – разные задачи
View-Switching Navigation – вторична
UI Composition – первична
Разделить задачи View-Switching Navigation и UI Composition
Это решение используется в Prism.Windows
TODO рассказать про навигацию и Composite UI, Что это разные задачи. CompositeUI не зависит от выбранного подхода к навигации
В списке слева – права и роли, при выборе элемента – отображение специализированной detail формы
Как это сделать при использовании MVVM без ViewSwitching?
Делает UI Composition более мощным (замена на рантайме вьюх) и используется для навигации