- PVSM.RU - https://www.pvsm.ru -

Portable Prism

Посвящается фанатам группы Microsoft Patterns&Practices [1] и просто любителям такой полезной штуки как Microsoft PRISM [2].

Разработчики, которые в своей практике встречались с Microsoft PRISM, вероятно, имеют двоякое мнение об этом фреймворке. С одной стороны, в своей по номеру 4-й, а по порядку 3-й, версии – это очень мощный и гибкий инструмент для создания композитных приложений, а с другой стороны довольно непонятная и запутанная библиотека. Но можно на PRISM взглянуть и просто как на реализацию шаблона MVVM, чем PRISM для Windows Phone по сути и является.

Мне такая реализация MVVM очень нравится и когда я познакомился с Portable Class Library, я понял, что мне нужен портативный PRISM. Благо исходники PRISM доступны и переделать его на Portable Library было не очень сложной задачей.

Портирование

Задача собственно состояла в том, чтобы вынести всё общее в портативную часть и всё остальное в специфичную для платформы. Но, кроме того, что мне нравится PRISM, мне ещё нравится использовать его с MEF, а MEF [3] как раз с появлением PCL2.0 появился и для WinRT в виде Microsoft.Composition [4].

К стати, кто не знает, Microsoft.Composition построен на PCL и при желании его можно построить для PCL и использовать в Windows Phone 8 или прямо в портативной библиотеке. Правда вот последней версии исходников, по которым построен NuGet пакет Microsoft.Composition, я на сайте проекта на Codeplex [5] не нашёл.

Так что расширения MEF для PRISM для WinRT пришлось хорошенько изменить с тем чтобы PRISM смог работать с Microsoft.Composition. Тем не менее большинство модульных тестов удалось оставить сделав небольшие изменения.

Абстрагирование и Fody

Кто фундаментально разбирался с тем как работает PRISM знает, что там есть композитные события работа которых требует Dispatcher, а он ведь разный на разных платформах. Кроме того в версии для .NET использовался тип WeakReference [6], которого нет на некоторых платформах. И мне не хотелось бы, вынуждать того, кто будет использовать Portable PRISM каждый раз писать какой-то инициализирующий код, который бы внедрил эти зависимости.

И тут я узнал, что у каждой .NET сборки есть инициализатор – фактически статический конструктор, который выполняется единожды при загрузке сборки в приложение, но так просто его не пропишешь… И тут мне на помощь пришёл великолепный инструмент австралийца Саймона Кроппа (Simon Cropp [7]), Fody [8].

Этот проект родился из проекта расширения для Visual Studio Notify Property Weaver [9], который позволял, используя Mono.Cecil после построения, переписать свойства классов которые были наследниками INotifyPropertyChanged так, чтобы они сами вызывали событие изменения свойства при изменении его значения.

Fody [8] стал более универсальным продолжением Notify Property Weaver [9]’а, к которому можно подключить разные подключаемые модули которые перепишут определённую часть сборки. Для Fody [8] уже написано [10] много полезных модулей [11], которые можно поставить через NuGet в конкретный проект. Одним из таких плагинов является ModuleInit.Fody [12], который умеет прописать в инициализатор сборки вызов метода Initialize статического класса ModuleInitializer.

    internal static class ModuleInitializer
    {
        public static void Initialize()
        {
            InitializeCompositePresentationEvent();
            InitializeWeakEventHandlerManager();
        }
 
        private static void InitializeCompositePresentationEvent()
        {
            var dispatcher = new Lazy<IDispatcherFacade>(() => new DefaultDispatcher());
            EventBase.InitializeDispatcher(dispatcher);
        }
 
        private static void InitializeWeakEventHandlerManager()
        {
            EventHandlerManager.Current = new WeakEventHandlerManager();
        }
    }

Чем я благополучно и воспользовался.

Забавно, но ModuleInitalizer'ы не работают в Windows Phone 7 [13]. И такое впечатление, что никто не собирается исправлять этот баг. Хорошо теперь хоть статические конструкторы работают в подключаемых сборках [14].

Особенности порта

WinRT
В версию для WinRT не включены регионы [15]. У меня не было в них необходимости, а написать адаптер для Frame не возможно, так что я решил эту функциональность не переносить. Тем не менее исходники в проекте есть. Так что, вдруг кому-то понадобится их добавить, вы можете это сделать.

Windows Phone 8
В PRISM для Windows Phone 8 я в общем то скопировал функциональность PRISM для Windows Phone 7 добавив лишь WeakEvent так как он теперь доступен в Windows Phone SDK 8.0 и удалил классы касающиеся AppBar так как реализованы они там крайне криво. Я думаю, что гораздо лучше для работы с AppBar использовать библиотеку Cimbalino [16].

Что сейчас доступно?

И так какие же NuGet пакеты есть:

Что дальше?

Я надеюсь, что мои пакеты будут полезны тем кому нравится PRISM или кто хочет что-либо реализованное с использованием PRISM перенести на новую платформу.

Если кому-то нужны другие части PRISM в виде портативной версии, например, расширения для Unity для WinRT вы можете клонировать проект Portable PRISM на GitHub [23] и добавить их. Если не сможете построить проект, пишите. Я ещё не разобрался, как настроить .gitignore так, чтобы информация о NuGet пакетах коммитилась, а сами пакеты – нет, и их можно было повторно скачать. Так что, кто знает, как это сделать, подскажите, пожалуйста.

Автор: XperiAndri

Источник [24]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/net/27161

Ссылки в тексте:

[1] группы Microsoft Patterns&Practices: http://pnp.azurewebsites.net/en-us/

[2] Microsoft PRISM: http://compositewpf.codeplex.com/

[3] MEF: http://mef.codeplex.com/

[4] Microsoft.Composition: http://nuget.org/packages/Microsoft.Composition/

[5] сайте проекта на Codeplex: http://mef.codeplex.com/SourceControl/list/changesets

[6] WeakReference: http://msdn.microsoft.com/en-us/library/system.weakreference.aspx

[7] Simon Cropp: http://simoncropp.com/

[8] Fody: http://visualstudiogallery.msdn.microsoft.com/074a2a26-d034-46f1-8fe1-0da97265eb7a

[9] Notify Property Weaver: http://visualstudiogallery.msdn.microsoft.com/bd351303-db8c-4771-9b22-5e51524fccd3

[10] написано: https://github.com/Fody

[11] полезных модулей: http://nuget.org/packages?q=fody

[12] ModuleInit.Fody: http://nuget.org/packages/ModuleInit.Fody/

[13] ModuleInitalizer'ы не работают в Windows Phone 7: https://connect.microsoft.com/VisualStudio/feedback/details/775602/wp7-1-1-module-initializers-are-not-executed-for-assemblies

[14] статические конструкторы работают в подключаемых сборках: https://connect.microsoft.com/VisualStudio/feedback/details/722944/windows-phone-static-constructor-is-not-executed-for-class-in-separate-assembly

[15] регионы: http://msdn.microsoft.com/en-us/library/ff921098(v=pandp.40).aspx

[16] Cimbalino: http://cimbalino.org/

[17] Portable PRISM — Portable: https://nuget.org/packages/PortablePrism.Portable/

[18] Portable PRISM — Portable — Interactivity: https://nuget.org/packages/PortablePrism.Portable.Interactivity/

[19] Portable PRISM — WinRT: https://nuget.org/packages/PortablePrism.WinRT/

[20] Portable PRISM — WinRT MEF extensions: https://nuget.org/packages/PortablePrism.WinRT.MEF/

[21] Portable PRISM — Windows Phone 8: https://nuget.org/packages/PortablePrism.WP8/

[22] Portable PRISM — Windows Phone 8 — Interactivity: https://nuget.org/packages/PortablePrism.WP8.Interactivity/

[23] проект Portable PRISM на GitHub: https://github.com/xperiandri/PortablePrism

[24] Источник: http://habrahabr.ru/post/169471/