Создание и регистрация Metro style компонента для WinRT

в 7:18, , рубрики: .net, metro, vs2012, Windows 8, WinRT, Блог компании DevExpress, метки: , , , , ,

Создание и регистрация Metro style компонента для WinRT Официальный релиз 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:

Создание и регистрация Metro style компонента для WinRT

В результате будет создан пустой проект с одним классом. Так как в нашем случае этот класс не понадобится, удалим файл Class1.cs из проекта:

Создание и регистрация Metro style компонента для WinRT

Затем добавим заготовку для нашего будущего компонента. Для этого в диалоге Add New Item выбираем новый шаблон – Templated Control – и задаем ему имя MyCustomControl:

Создание и регистрация Metro style компонента для WinRT

После этих действий в проекте появится два новых файла:

  • 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):

Создание и регистрация Metro style компонента для WinRT

Теперь к этому проекту добавим ссылку (типа Project Reference) на нашу сборку MyCustomControls:

Создание и регистрация Metro style компонента для WinRT

Далее необходимо изменить содержимое файла 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 style компонента для WinRT

Теперь запускаем наш проект и видим индикатор загрузки в стиле Metro – а это значит, что наш компонент работоспособен!

Создание и регистрация Metro style компонента для WinRT

Создание 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.

Создание и регистрация Metro style компонента для WinRT

Чтобы проверить, всё ли работает в этом случае, модифицируем файл MainPage.xaml аналогично тому, как мы делали в предыдущем тестовым примере, затем собираем и запускаем проект – и видим наш индикатор загрузки в действии!

Полезные ссылки

Более подробную информацию о том, как создать свой Extension SDK, можно найти по следующий ссылке:
http://msdn.microsoft.com/library/hh768146(v=VS.110).aspx

Если вы хотите глубже познакомиться с WinRT, вот ссылки на другие полезные ресурсы:

Автор: AlexKravtsov

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js