Приложения для
Windows Phone
Как мы это делаем

Григорий Никонов,
Actis® Wunderman.
Обо мне
На данный момент руковожу разработкой мобильных
приложений агентства Actis Wunderman, в котором тружусь с
момента появления на свет агентства Actis, позже
присоединившегося к сети Wunderman.


Ранее занимался разработкой, созданием и внедрением
интернет-проектов.
Наши работы
Мы занимаемся разработкой приложений для ведущих
платформ около трех лет. Вот, что мы сделали для Windows
Phone:
•КиноПоиск
•Concert.ru
•ЛитРес
Несколько неназываемых проектов скоро должны быть
опубликованы, тогда мы их назовѐм.
Наши работы: КиноПоиск
Наши работы: Concert.ru
Наши работы: ЛитРес
Мы – ленивые
И поэтому создали несколько инструментов, которые
позволяют нам экономить время и усилия:
•Фреймворк работы с сущностями и коллекциями
•Фреймворк моделей представлений
•Фреймворк представлений для Windows Phone и других
платформ
•T4-генераторы кода
Кроме того, сервер непрерывной интеграции и тесты
позволяют нам не заботиться о проблемах внесения
изменений в код и координировать совместную работу
Данные
Данные можно разделить на две категории – сущности и
коллекции сущностей
И сущности и коллекции сущностей бывают
идентифицируемые и неидентифицируемые
Данные
Сценарии использования источников данных в мобильных
приложениях, в порядке уменьшения частоты использования:
•Получить коллекцию заголовков данных
•Получить конкретную сущность
•Выполнить единичное действие с источником данных
•Отправить изменѐнную сущность


«Мобильность» платформы накладывает некоторые
ограничения на возможность и целесообразность передачи
больших объѐмов данных
Сущности
События изменения свойств:
ObservableObject


Обновление и клонирование:
XObject, XObject<T>


Ключи для идентификации объектов:
XKey
Коллекции
Интеллектуальное обновление:
XCollection<T>


Применение фильтров:
XFilteredCollection<T>


Объединение и разделение:
XCombinedCollection<T>, XSubRangeCollection<T>
Кэширование
Запросы как идентификация коллекций:
XQuery<T>


Собственно кэш:
XCache<T>
Пример: Свойства
class Person : XObject
{
string _name;
XCollection<Person> _children;
public string Name
{
    get { return _name; }
    set { SetProperty( ref _name, value, “Name” ); }
}

public XCollection<Person> Children
{
    get { return _children; }
    set { SetProperty( ref _children, value ); }
}
}
Пример: ProcessCopy
class Person : XObject
{
protected override void ProcessCopy(
    XObject source, bool cloning, bool deepCloning )
{
    base.ProcessCopy( source, cloning, deepCloning );

    Person other = (Person) source;

    _name = other._name;

    ProcessCopyProperty(
        ref _children, other._children,
        cloning, deepCloning );
}
}
Пример: Клонирование
Person person = new Person
{
Name = “John”,
Children = new XCollection<Person>
    {
       new Person { Name = “Bob” }
    }
};

Person softClone = (Person) person.Clone( false );
Person deepClone = (Person) person.Clone( true );

person.Children[0].Name = “Mary”;

softClone.Children[0].Name // “Mary”
deepClone.Children[0].Name // “Bob”
Пример: Обновление
Person person1 = new Person { Name = “John” }
Person person2 = new Person { Name = “Mary” }
person1.Update( person2 );

person1.Name // “Mary”

XCollection<Person> l1 = new XCollection<Person>() { … };
XCollection<Person> l2 = new XCollection<Person>() { … };

var result = l1.Update( l2 );
Пример: Коллекции
XCollection<Person> l1 = new XCollection<Person>() { … };
XCollection<Person> l2 = new XCollection<Person>() { … };

var softClone = l1.Clone( false );
var deepClone = l1.Clone( true );

var result = l1.Update( l2 );
Пример: Хитрые коллекции
XCollection<Person> studentsOfClassA = …;
XCollection<Person> studentsOfClassB = …;

var firstThreeStudentsOfClassA =
new XSubRangeCollection( studentsOfClassA, 0, 3 );

var firstTwoStudentsOfClassB =
new XSubRangeCollection( studentsOfClassB, 0, 2 );
var topStudents =
new XCombinedCollection(
    firstThreeStudentsOfClassA,
    firstTwoStudentsOfClassB );
Генератор сущностей
<Entity Name="FeedChannel" BaseType="XObject” XKeyProperties="Link">
<Property Name="Title" Type="string" SerializationName="title"/>
<Property Name="Description" Type="string”
    SerializationName="description"/>
<Property Name="Link" Type="string" SerializationName="link"/>
<Property Name="Image" Type="ChannelImage”
    SerializationName="image"/>

<Property Name="Items”
    Type=”XCollection” TypeGenericArguments="ChannelItem”
    SerializationName="item"/>
</Entity>



Поддержка XML/JSON сериализации
Демонстрация
Сгенерированные классы, содержащие ключевые элементы,
необходимые для эффективной работы с данными:
•Правильное обновление данных
•Правильное клонирование данных
•Выборка с помощью ключей в коллекциях и кэше
Модели представлений
Предназначены для получения и преобразования данных,
необходимых представлениям, а также для выполнения других
действий над этими данными.
Наиболее частые операции в мобильных приложениях –
загрузка данных (списки или отдельные сущности) для
представления их пользователю.
Работа с источниками данных должна быть асинхронной –
нельзя блокировать поток пользовательского интерфейса.
Необходимо учитывать возможность досрочного прекращения
выполняемых операций – по разным причинам.
Сессии
Всѐ «управляемое» общение модели (модели представления)
с внешним миром происходит в рамках сессии
Сессия содержит параметры, необходимые для доступа к
данным
Сессия содержит жетон, используемый для прекращения
асинхронных задач (CancellationToken)
Обработкой сессии занимается модель
Работа с сессией
Создание
var session = CreateSession()
.AddParameter( “userName”, “John” )
.AddParameter( “age”, 48 );

Доступ к параметрам
var userName = session.Parameters.Get<string>( “userName” );
var age = session.Parameters.Get<int>( “age” );
var sex = session.Parameters.Get<string>( “sex”, “male” );

Обработка
await viewModel.Load( session );
Откуда она знает, что делать?
Виртуальные методы
ShouldLoadSession
LoadSession
Части
RegisterPart
   string part,
   Func<Session, Task> processor,
   Func<Session, bool> checker,
   bool loadIfNoPartsSpecified
Типичная модель
Конструктор
Получает сервисы через DI
Регистрирует части
Создает команды
Методы обработки частей
Проверяют необходимость обработки сессии
Осуществляют доступ/обновление данных
Модель сущности
Использует расширенную сессию, которая включает в себя
ключ, идентифицирующий объект: EntitySession
Регистрирует методы для части, связанной с обработкой
сущности: ShouldLoadEntity и LoadEntity.
Объявляет свойство Entity
Типичная модель сущности
Конструктор
Получает сервисы
Создает команды
Метод LoadEntity
Загружает данные из внешнего источника или из кэша
Присваивает значение свойству Entity
INavigationService
Один из самых важных сервисов, доступных моделям
Определяет независимый от платформы способ навигации
между видами
ns.Navigate( “PersonView”, Parameters.Create( “Id”, 1 ) );

Позволяет создавать и использовать команды навигации:
ViewDetails = new NavigationCommand(
ns,
“DetailedView” );

PersonSelected = new NavigationCommand<Person>(
ns,
“PersonView”,
person => person.KeyParameter() );
Другие сервисы
IDataExchangeService
Информирование об обмене данными
IViewModelExceptionHandlingService
IExceptionHandlingService
Унифицированная обработка исключений
Представления
PhoneApplication – наследник Application
Регистрация сервисов
Обработка ошибок уровня приложения
Page
Управление жизненным циклом
OnPageCreated, OnPageDestroyed,
OnPageAsleep, OnPageAwaken, OnPageResurrected
Доступ к параметрам
ViewParameters
Контекст для связывания данных
CreateDataContext
Атрибутирование для навигации
[View( “UserView” )]
[ViewParameter( “userName”, typeof( string ) )]
ViewModelPage<TViewModel>
Страница с созданной моделью
Начальная загрузка данных
CreateDataSession, CreateDataSessionAsync
OnDataLoadComplete, OnDataLoadFailed
Обработка нештатных ситуаций (FAS)
Управление областью жизни модели
Связывание данных в XAML
<TextBlock Text=“{Binding ViewModel.Title}”/>
EntityPage
Автоматически выбирает ключ из параметров и создает
сессию для загрузки сущности.
Но это еще не всё!
Генератор классов-заглушек и частичных классов-
представлений:
<View Name=“MainView”/>
<View Name=“FeedChannelView” Entity=“FeedChannel”/>

Во многих случаях файл View.xaml.cs не нужен, всѐ делается
автомагически
Генератор константных имен представлений и параметров, а
также методов для создания параметров навигации
Но и это еще не всё!
Декораторы страниц используются для выполнения
однообразных действий со страницами, например для показа
сообщений об ошибках, исчезновении сетевого подключения и
т.п.
Встроенный механизм обработки страниц, для которых нужна
аутентификация – атрибут RequiresAuthentication
Теперь доступно всем
Мы выпустили наши базовые библиотеки в виде NuGet-
пакетов – ключевое слово Digillect (Include Prereleases).
Для интересующихся анатомическими деталями – исходные
коды доступны на GitHub:
https://github.com/organizations/Digillect
https://github.com/Digillect/object-model
https://github.com/Digillect/mvvm
https://github.com/Digillect/mvvm-wp
Google-группа для вопросов и обсуждений:
https://groups.google.com/d/forum/digillect
Лицензия MIT.
Вопросы?


Григорий Никонов,
Actis® Wunderman
gregoryn@actis.ru
(495) 234-0009
http://www.actis.ru/

Приложения для Windows Phone: как мы это делаем #codefest

  • 1.
    Приложения для Windows Phone Какмы это делаем Григорий Никонов, Actis® Wunderman.
  • 2.
    Обо мне На данныймомент руковожу разработкой мобильных приложений агентства Actis Wunderman, в котором тружусь с момента появления на свет агентства Actis, позже присоединившегося к сети Wunderman. Ранее занимался разработкой, созданием и внедрением интернет-проектов.
  • 3.
    Наши работы Мы занимаемсяразработкой приложений для ведущих платформ около трех лет. Вот, что мы сделали для Windows Phone: •КиноПоиск •Concert.ru •ЛитРес Несколько неназываемых проектов скоро должны быть опубликованы, тогда мы их назовѐм.
  • 4.
  • 5.
  • 6.
  • 7.
    Мы – ленивые Ипоэтому создали несколько инструментов, которые позволяют нам экономить время и усилия: •Фреймворк работы с сущностями и коллекциями •Фреймворк моделей представлений •Фреймворк представлений для Windows Phone и других платформ •T4-генераторы кода Кроме того, сервер непрерывной интеграции и тесты позволяют нам не заботиться о проблемах внесения изменений в код и координировать совместную работу
  • 8.
    Данные Данные можно разделитьна две категории – сущности и коллекции сущностей И сущности и коллекции сущностей бывают идентифицируемые и неидентифицируемые
  • 9.
    Данные Сценарии использования источниковданных в мобильных приложениях, в порядке уменьшения частоты использования: •Получить коллекцию заголовков данных •Получить конкретную сущность •Выполнить единичное действие с источником данных •Отправить изменѐнную сущность «Мобильность» платформы накладывает некоторые ограничения на возможность и целесообразность передачи больших объѐмов данных
  • 10.
    Сущности События изменения свойств: ObservableObject Обновлениеи клонирование: XObject, XObject<T> Ключи для идентификации объектов: XKey
  • 11.
  • 12.
    Кэширование Запросы как идентификацияколлекций: XQuery<T> Собственно кэш: XCache<T>
  • 13.
    Пример: Свойства class Person: XObject { string _name; XCollection<Person> _children; public string Name { get { return _name; } set { SetProperty( ref _name, value, “Name” ); } } public XCollection<Person> Children { get { return _children; } set { SetProperty( ref _children, value ); } } }
  • 14.
    Пример: ProcessCopy class Person: XObject { protected override void ProcessCopy( XObject source, bool cloning, bool deepCloning ) { base.ProcessCopy( source, cloning, deepCloning ); Person other = (Person) source; _name = other._name; ProcessCopyProperty( ref _children, other._children, cloning, deepCloning ); } }
  • 15.
    Пример: Клонирование Person person= new Person { Name = “John”, Children = new XCollection<Person> { new Person { Name = “Bob” } } }; Person softClone = (Person) person.Clone( false ); Person deepClone = (Person) person.Clone( true ); person.Children[0].Name = “Mary”; softClone.Children[0].Name // “Mary” deepClone.Children[0].Name // “Bob”
  • 16.
    Пример: Обновление Person person1= new Person { Name = “John” } Person person2 = new Person { Name = “Mary” } person1.Update( person2 ); person1.Name // “Mary” XCollection<Person> l1 = new XCollection<Person>() { … }; XCollection<Person> l2 = new XCollection<Person>() { … }; var result = l1.Update( l2 );
  • 17.
    Пример: Коллекции XCollection<Person> l1= new XCollection<Person>() { … }; XCollection<Person> l2 = new XCollection<Person>() { … }; var softClone = l1.Clone( false ); var deepClone = l1.Clone( true ); var result = l1.Update( l2 );
  • 18.
    Пример: Хитрые коллекции XCollection<Person>studentsOfClassA = …; XCollection<Person> studentsOfClassB = …; var firstThreeStudentsOfClassA = new XSubRangeCollection( studentsOfClassA, 0, 3 ); var firstTwoStudentsOfClassB = new XSubRangeCollection( studentsOfClassB, 0, 2 ); var topStudents = new XCombinedCollection( firstThreeStudentsOfClassA, firstTwoStudentsOfClassB );
  • 19.
    Генератор сущностей <Entity Name="FeedChannel"BaseType="XObject” XKeyProperties="Link"> <Property Name="Title" Type="string" SerializationName="title"/> <Property Name="Description" Type="string” SerializationName="description"/> <Property Name="Link" Type="string" SerializationName="link"/> <Property Name="Image" Type="ChannelImage” SerializationName="image"/> <Property Name="Items” Type=”XCollection” TypeGenericArguments="ChannelItem” SerializationName="item"/> </Entity> Поддержка XML/JSON сериализации
  • 20.
    Демонстрация Сгенерированные классы, содержащиеключевые элементы, необходимые для эффективной работы с данными: •Правильное обновление данных •Правильное клонирование данных •Выборка с помощью ключей в коллекциях и кэше
  • 21.
    Модели представлений Предназначены дляполучения и преобразования данных, необходимых представлениям, а также для выполнения других действий над этими данными. Наиболее частые операции в мобильных приложениях – загрузка данных (списки или отдельные сущности) для представления их пользователю. Работа с источниками данных должна быть асинхронной – нельзя блокировать поток пользовательского интерфейса. Необходимо учитывать возможность досрочного прекращения выполняемых операций – по разным причинам.
  • 22.
    Сессии Всѐ «управляемое» общениемодели (модели представления) с внешним миром происходит в рамках сессии Сессия содержит параметры, необходимые для доступа к данным Сессия содержит жетон, используемый для прекращения асинхронных задач (CancellationToken) Обработкой сессии занимается модель
  • 23.
    Работа с сессией Создание varsession = CreateSession() .AddParameter( “userName”, “John” ) .AddParameter( “age”, 48 ); Доступ к параметрам var userName = session.Parameters.Get<string>( “userName” ); var age = session.Parameters.Get<int>( “age” ); var sex = session.Parameters.Get<string>( “sex”, “male” ); Обработка await viewModel.Load( session );
  • 24.
    Откуда она знает,что делать? Виртуальные методы ShouldLoadSession LoadSession Части RegisterPart string part, Func<Session, Task> processor, Func<Session, bool> checker, bool loadIfNoPartsSpecified
  • 25.
    Типичная модель Конструктор Получает сервисычерез DI Регистрирует части Создает команды Методы обработки частей Проверяют необходимость обработки сессии Осуществляют доступ/обновление данных
  • 26.
    Модель сущности Использует расширеннуюсессию, которая включает в себя ключ, идентифицирующий объект: EntitySession Регистрирует методы для части, связанной с обработкой сущности: ShouldLoadEntity и LoadEntity. Объявляет свойство Entity
  • 27.
    Типичная модель сущности Конструктор Получаетсервисы Создает команды Метод LoadEntity Загружает данные из внешнего источника или из кэша Присваивает значение свойству Entity
  • 28.
    INavigationService Один из самыхважных сервисов, доступных моделям Определяет независимый от платформы способ навигации между видами ns.Navigate( “PersonView”, Parameters.Create( “Id”, 1 ) ); Позволяет создавать и использовать команды навигации: ViewDetails = new NavigationCommand( ns, “DetailedView” ); PersonSelected = new NavigationCommand<Person>( ns, “PersonView”, person => person.KeyParameter() );
  • 29.
    Другие сервисы IDataExchangeService Информирование обобмене данными IViewModelExceptionHandlingService IExceptionHandlingService Унифицированная обработка исключений
  • 30.
    Представления PhoneApplication – наследникApplication Регистрация сервисов Обработка ошибок уровня приложения
  • 31.
    Page Управление жизненным циклом OnPageCreated,OnPageDestroyed, OnPageAsleep, OnPageAwaken, OnPageResurrected Доступ к параметрам ViewParameters Контекст для связывания данных CreateDataContext Атрибутирование для навигации [View( “UserView” )] [ViewParameter( “userName”, typeof( string ) )]
  • 32.
    ViewModelPage<TViewModel> Страница с созданноймоделью Начальная загрузка данных CreateDataSession, CreateDataSessionAsync OnDataLoadComplete, OnDataLoadFailed Обработка нештатных ситуаций (FAS) Управление областью жизни модели Связывание данных в XAML <TextBlock Text=“{Binding ViewModel.Title}”/>
  • 33.
    EntityPage Автоматически выбирает ключиз параметров и создает сессию для загрузки сущности.
  • 34.
    Но это ещене всё! Генератор классов-заглушек и частичных классов- представлений: <View Name=“MainView”/> <View Name=“FeedChannelView” Entity=“FeedChannel”/> Во многих случаях файл View.xaml.cs не нужен, всѐ делается автомагически Генератор константных имен представлений и параметров, а также методов для создания параметров навигации
  • 35.
    Но и этоеще не всё! Декораторы страниц используются для выполнения однообразных действий со страницами, например для показа сообщений об ошибках, исчезновении сетевого подключения и т.п. Встроенный механизм обработки страниц, для которых нужна аутентификация – атрибут RequiresAuthentication
  • 36.
    Теперь доступно всем Мывыпустили наши базовые библиотеки в виде NuGet- пакетов – ключевое слово Digillect (Include Prereleases). Для интересующихся анатомическими деталями – исходные коды доступны на GitHub: https://github.com/organizations/Digillect https://github.com/Digillect/object-model https://github.com/Digillect/mvvm https://github.com/Digillect/mvvm-wp Google-группа для вопросов и обсуждений: https://groups.google.com/d/forum/digillect Лицензия MIT.
  • 38.