Официальный релиз Windows 8 приближается с каждым днём, и всё больше разработчиков задумывается о том, чтобы создать своё приложение в стиле Metro. А если же вы делаете сразу несколько таких приложений, то скорее всего у вас возникнет потребность использовать один и тот же код в разных проектах.
В этой статье приведена пошаговая инструкция по созданию простого Metro style компонента, а также особенности регистрации такой библиотеки для дальнейшего использования в WinRT проектах.
В качестве примера компонента мы выбрали анимированный индикатор загрузки в стиле Metro, похожий на тот, который многие из нас уже видели в новой версии Windows. К концу этой статьи вы будете не только знать всё о регистрации компонентов, но и иметь возможность добавить готовый индикатор загрузки в своё Metro приложение.
Системные требования
Если вы ещё не успели написать свою первую программу для Windows 8, то удостоверьтесь, что ваша среда разработки удовлетворяет следующим требованиям:
- Разработка должна вестись в операционной системе Windows 8. На момент написания этой статьи Windows 8 доступна в стадии Release Preview и её можно скачать по этой ссылке:
http://www.microsoft.com/visualstudio/11/ru-ru/downloads - Для разработки вам понадобится среда разработки Visual Studio 2012, которая на данный момент находится в стадии Release Candidate и доступна для скачивания с http://www.microsoft.com/visualstudio/11/ru-ru/downloads.
Если у вас нет возможности использовать профессиональную версию Visual Studio, вы всегда можете бесплатно установить себе Visual Studio Express 2012 for Windows 8. В этой статье все действия будут приводиться для интерфейса профессиональной версии Visual Studio 2012.
Создание библиотеки
Итак, мы запустили Visual Studio 2012 и готовы сделать свой первый Metro-style компонент.
Для этого создадим новый проект типа Class Library (Metro style apps) и назовём его MyCustomControls:
В результате будет создан пустой проект с одним классом. Так как в нашем случае этот класс не понадобится, удалим файл Class1.cs из проекта:
Затем добавим заготовку для нашего будущего компонента. Для этого в диалоге Add New Item выбираем новый шаблон – Templated Control – и задаем ему имя MyCustomControl:
После этих действий в проекте появится два новых файла:
- MyCustomControl.cs, содержащий определение нашего компонента как наследника от контрола:
namespace MyCustomControls { public sealed class MyCustomControl : Control { public MyCustomControl() { this.DefaultStyleKey = typeof(MyCustomControl); } } }
Заменим его на код, представленный ниже:
namespace MyCustomControls { public sealed class MyCustomControl : Control { const double radius = 30; public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(Geometry), typeof(MyCustomControl), new PropertyMetadata(null)); public Geometry Data { get { return (Geometry)GetValue(DataProperty); } set { SetValue(DataProperty, value); } } DispatcherTimer timer; double progress = 0.0; Size arrangeSize = new Size(0, 0); DateTime lastTime = DateTime.Now; public MyCustomControl() { this.DefaultStyleKey = typeof(MyCustomControl); timer = new DispatcherTimer(); timer.Tick += timer_Tick; timer.Interval = TimeSpan.FromMilliseconds(5); timer.Start(); } void timer_Tick(object sender, object e) { DateTime time = DateTime.Now; progress += 0.5 * (time - lastTime).TotalSeconds; lastTime = time; if (progress > 1) progress -= 1; Data = CreateGeometry(progress); } double CalcAngle(double progress) { double factor = 0.5 * Math.Cos(Math.PI * progress - Math.PI) + 0.5; return 2 * Math.PI * factor; } double CalcDistance(double angle) { return 0.3 * (Math.PI - Math.Abs(Math.PI - angle)); } Geometry CreateGeometry(double progress) { double angle = CalcAngle(progress); double distance = CalcDistance(angle); GeometryGroup newGeometry = new GeometryGroup() { FillRule = FillRule.Nonzero }; for (int i = 3; i > -4; i--) { Point location = new Point(0.5 * arrangeSize.Width + radius * Math.Cos(angle + i * distance - Math.PI / 2), 0.5 * arrangeSize.Height + radius * Math.Sin(angle + i * distance - Math.PI / 2)); newGeometry.Children.Add(new EllipseGeometry() { Center = location, RadiusX = 5, RadiusY = 5 }); } return newGeometry; } protected override Size MeasureOverride(Size availableSize) { base.MeasureOverride(availableSize); return new Size(!double.IsInfinity(availableSize.Width) ? availableSize.Width : 0, !double.IsInfinity(availableSize.Height) ? availableSize.Height : 0); } protected override Size ArrangeOverride(Size arrangeBounds) { arrangeSize = arrangeBounds; return base.ArrangeOverride(arrangeBounds); } } }
- ThemesGeneric.xaml, где находится описание стиля, который будет применен по умолчанию к нашему контролу. Впишем в разметку элемент Path:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:MyCustomControls"> <Style TargetType="local:MyCustomControl"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:MyCustomControl"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <Path Fill="Aqua" Data="{Binding Path=Data, RelativeSource={RelativeSource TemplatedParent} }"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
Дальше можно быстро протестировать работу написанного компонента. Для этого добавим еще один проект типа Blank App (XAML):
Теперь к этому проекту добавим ссылку (типа Project Reference) на нашу сборку MyCustomControls:
Далее необходимо изменить содержимое файла MainPage.xaml, как показано ниже:
<Page
x:Class="App1.MainPage"
IsTabStop="false"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:my="using:MyCustomControls"
mc:Ignorable="d">
<Grid Background="White">
<my:MyCustomControl />
</Grid>
</Page>
Затем сделаем стартовым приложение App1:
Теперь запускаем наш проект и видим индикатор загрузки в стиле Metro – а это значит, что наш компонент работоспособен!
Создание Extension SDK
Теперь можно перейти непосредственно к созданию собственного Extension SDK. С помощью Extension SDK можно объединить несколько библиотек в один набор, который можно будет подключить в проект Visual Studio, добавив одну ссылку на весь SDK сразу.
Для начала создадим на жестком диске следующую структуру каталогов, которая будет содержать всё необходимое для нашего SDK:
MySDK
— — 1.0
— — — — ReferencesCommonConfigurationneutralMyCustomControls.dll
— — — — RedistCommonConfigurationneutralMyCustomControls.pri
— — — — RedistCommonConfigurationneutralMyCustomControlsThemesgeneric.xaml
— — — — SDKManifest.xml
В этой структуре MySDK – это корневая папка, содержащая все остальные файлы SDK. Она может иметь любое имя, которое отражает название вашего SDK. 1.0 – это версия вашего SDK.
Директория References должна содержать все модули, которые будут входить в SDK, собранные в соответствующей конфигурации и под определенную архитектуру. То есть следующий уровень определяет конфигурацию, и возможно всего три варианта: Debug, Retail и CommonConfiguration. Последний уровень, соответственно, говорит о том, для какой архитектуры были собраны данные модули: neutral, х64, х86 и ARM. В рассматриваемом случае была сделана сборка в Debug или Release под AnyCPU.
В директории Redist располагаются файлы, которые необходимы для отладки и выполнения, и они будут упакованы в пакет. И опять всё зависит от конфигурации и архитектуры – точно так же, как и для References.
Файл SDKManifest.xml должен иметь следующее содержимое:
<?xml version="1.0" encoding="utf-8" ?>
<FileList DisplayName="My Custom Controls" ProductFamilyName="My Controls" MinVSVersion="11.0" MinToolsVersion="4.0" CopyRedistToSubDirectory="." AppliesTo="WindowsAppContainer+WindowsXAML+Managed">
<File Reference="MyCustomControls.dll">
<ContainsControls>True</ContainsControls>
</File>
</FileList>
Этот файл описывает все сборки, которые находятся в папке References. Параметр CopyRedistToSubDirectory задает, куда будут скопированы файлы из папки Redist относительно корня пакета. Мы установили его как "." – это означает, что все файлы будут скопированы в корень пакета.
Регистрация Extension SDK
Теперь вы можете зарегистрировать ваш SDK одним из следующих способов:
- скопировать папку MySDK в папку "%ProgramFiles%Microsoft SDKsWindowsv8.0Extension SDKs"
- добавить ключ в реестр, который будет содержать путь к нашему SDK. Приведу пример *.reg файла, который будет добавлять соответствующие данные в реестр:
REGEDIT4 [HKEY_LOCAL_MACHINESOFTWAREMicrosoftMicrosoft SDKsWindowsv8.0ExtensionSDKsMySDK1.0] @="C:\Sources\MySDK\1.0"
После того, как SDK был создан и зарегистрирован, можно создать новый тестовый проект типа Blank App (XAML).
При этом мы видим, что при добавлении ссылки на MyCustomControls.dll в разделе Windows-> Extentions будет виден MySDK.
Чтобы проверить, всё ли работает в этом случае, модифицируем файл MainPage.xaml аналогично тому, как мы делали в предыдущем тестовым примере, затем собираем и запускаем проект – и видим наш индикатор загрузки в действии!
Полезные ссылки
Более подробную информацию о том, как создать свой Extension SDK, можно найти по следующий ссылке:
http://msdn.microsoft.com/library/hh768146(v=VS.110).aspx
Если вы хотите глубже познакомиться с WinRT, вот ссылки на другие полезные ресурсы:
- Центр разработки Windows 8
msdn.microsoft.com/ru-ru/windows/ - Windows Metro Style Forums
social.msdn.microsoft.com/Forums/en-US/category/windowsapps - Windows 8 Metro style App Samples
code.msdn.microsoft.com/windowsapps - DevExpress — производитель визуальных компонентов для платформы .NET, включая WinRT
www.devexpress.com
Автор: AlexKravtsov