Размер шрифта:
Расширение, изменение и создание элементов управления на платформе UWP. Часть 1
Play

Расширение, изменение и создание элементов управления на платформе UWP. Часть 1

В 2006 году вместе с .NET 3.0 разработчикам были предоставлены программные платформы WPF и Silverlight. На протяжении следующих десяти лет Microsoft выпускала новые версии своей операционной системы и соответствующие им платформы. И вот, в 2016 году вместе с Windows 10 была выпущена Universal Windows Platform.

Все платформы отличались в той или степени возможностями API, но общий для них всех язык разметки XAML оставался практически неизменным. Поэтому все разработчики, вне зависимости от того, на какой платформе они работают, сталкиваются с одними и теми же задачами: расширение или изменение существующих, а также разработка новых элементов управления. Это очень важные навыки, необходимые для разработки приложений, удовлетворяющих требованиям дизайна и функциональности.

Эти задачи обусловлены тем, что на любой платформе разработчик располагает ограниченным набором элементов управления необходимых для разработки приложений. Его инструментарий составляют элементы из поставки Microsoft (в случае с UWP — Windows Universal Platform SDK) и от сторонних поставщиков или разработчиков. Даже все вместе они не могут покрыть всех требований, которые появляются при разработке приложений. Имеющиеся элементы управления могут не устраивать по ряду причин: внешний вид, поведение или функционирование. К сожалению, по сей день нет единого источника информации, который подробно и доступно освещал бы решения данных задач. Все, что остается разработчикам на протяжении длительного времени — собирать информацию в интернете крупица за крупицей.

Целью данной серии из трех статей является систематизация способов изменения, расширения и создания новых элементов управления. Часть 1. Расширение существующих элементов управления

В первой части пойдет речь о расширении существующих элементов управления без вмешательства в их внутреннее устройство.

Предположим, что общее поведение и функционирование элемента управления устраивает разработчика, но его необходимо расширить. Так, например, элемент управления TextBox предоставляет возможность ввода данных, но лишен функционала валидации. Самый простой способ получить требуемый результат заключается в добавлении логики в code-behind представления (View) содержащей этот TextBox.

Однако разработка на UWP предполагает использование архитектурного паттерна MVVM, одна из главных целей которого – отделение логики от представления. Следовательно, она должна быть инкапсулирована либо во ViewModel представления, либо в новый элемент управления взаимодействие, с которым будет осуществляться как с черным ящиком без нарушения принципов MVVM.

Таким образом, решение, представленное в листинге выше, подходит только в случае великой лени разработчика, уверенного в том, что на последующих стадиях разработки оно ему не аукнется. В случае же, если подобная валидация в рамках приложения потребуется более чем в одном месте, то это является прямым признаком того, что необходимо вынести данную логику в отдельную сущность.

Существует два способа расширения элементов управления без вмешательства в их внутренее строение и функционирование, реализацию которых можно сравнить с паразитизмом – присоединенные свойства и поведения.

Присоединенные Свойства (Attached Properties)

Присоединенное свойство – разновидность свойств зависимости, определяемое в отдельном классе и присоединяемое к целевому объекту на уровне XAML.

Рассмотрим механизм работы присоединенных свойств на вышеуказанном примере валидации TextBox для страницы регистрации.

Невалидная и валидная формы регистрации

Определим класс TextBoxExtensions, содержащий следующие присоединенные свойства:

1. RegexPattern – свойство, принимающее на вход строку шаблона валидации RegEx. В случае, если строка пустая считаем, что валидация поля ввода не требуется. 2. IsValid – свойство, содержащее значение текущего статуса валидации поля ввода на основании заданного в свойстве RegexPattern шаблона.

Также этот класс содержит метод OnRegexPatternChanged, срабатывающий при изменении значения свойства RegexPattern. Если его значение не пустое, то подписываемся на событие TextChanged элемента управления TextBox, в контексте которого работают свойства RegexPattern и IsValid.

В обработчике события Textbox_TextChanged вызываем метод ValidateText, валидирующий строку по переданному шаблону. Его результат присваиваем свойству IsValid.

Далее привязываем эти свойства к полям ввода в разметке и задаем значения свойства RegexPattern.

Имеем чистый сode-behind.

И логику доступности кнопки регистрации на уровне ViewModel.

Листинг класса PasswordBoxExtensions опущен, т.к. повторяет класс TextBoxExtensions чуть менее, чем полностью и существует только лишь по той причине, что оба элемента управления наследуются не от некоего абстрактного класса TextInput, от которого они могли бы получить общие поля и события, а от слишком общего класса Control.

Благодаря присоединенным свойствам, нам удалось расширить функционал существующих классов TextBox и PasswordBox без вмешательства в их внутренее строение. И нам даже не потребовалось порождать новый класс-потомок от них, что не всегда возможно.

Поведения (Behaviors)

Поведения появились в Expression Blend 3 с целью предоставить разработчикам механизм решения таких задач, возникающих на стороне пользовательского интерфейса, как: анимации, визуальные эффекты, drag-and-drop и т.п.

UWP не поставляет с собой библиотеку для работы с поведениями. Будучи частью Expression Blend SDK, её необходимо устанавливать отдельно, например, через Nuget.

Предположим, что мы работаем с элементом управления FlipView и требуется, чтобы при его пролистывании новый элемент воспроизводил анимацию появления.

Анимация поведения

Определим класс FlipViewItemFadeInBehavior, наследуемый от класса BehaviorT, где T – имя класса, к которому или потомкам которого можно добавлять требуемое поведение.

В нем переопределяем метод OnAttached, в котором подписываемся на событие SelectionChanged ассоциируемого объекта типа FlipView.

В обработчике события FlipView_SelectionChanged привязываем требуемую анимацию к новому элементу и запускаем её. Время воспроизведения анимации можем параметризовать определив свойство Duration.

Теперь мы готовы добавить данное поведение к требуемым элементам управления в разметке.

Таким образом, нам удалось вынести логику анимации в отдельную сущность с последующей возможностью использования через определение в разметке.

Оба рассмотренных механизма расширяют существующие элементы управления и важно четко понимать, когда и какой механизм использовать.

Если необходимо расширить элемент управления какой-то логикой, то это признак того, что результата можно достичь посредством присоединяемых свойств. Если же элементу управления нужно предоставить какой-то визуальный эффект или анимацию, то стоит обратить внимание на механизм поведений.

📎📎📎📎📎📎📎📎📎📎