Строка приложения в WinRT

137

Строка приложения (application bar) Windows 8 предназначена для реализации доступа к командам и настройкам программы примерно по тому же принципу, что и в традиционных меню и панелях инструментов. Строка приложения представлена классом AppBar, а чтобы вызвать ее, следует провести пальцем у верхнего или нижнего края экрана. Строка приложения может располагаться как у верхнего, так и у нижнего края. При выборе команды она часто исчезает с экрана, но это не обязательно.

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

Класс Page определяет два свойства с именами TopAppBar и BottomAppBar, которым обычно в XAML задаются теги AppBar. Класс AppBar является производным от ContentControl, и обычно свойству Content задается панель, содержащая элементы управления, располагающиеся на строке приложения. AppBar не имеет фиксированной высоты: высота зависит от расположенных на строке элементов управления.

Безусловно, знакомиться с использованием строки приложений в реальных программах лучше всего на примере стандартных приложений Windows 8. Чаще всего встречаются строки приложений, состоящие из ряда круглых элементов управления Button, но Internet Explorer для Windows 8 демонстрирует, что строка приложений может содержать разнообразные элементы управления. В Internet Explorer нижняя строка приложения содержит поле TextBox для ввода URL-адреса, а на верхней строке приложения отображается история посещенных веб-страниц.

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

<Page...>

    <Grid Background="LightGray">
        <TextBlock Name="textBlock"
                   Text="Нестандартный AppBar"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   FontSize="{Binding ElementName=slider, Path=Value}" />
    </Grid>

    <Page.TopAppBar>
        <AppBar Name="topAppBar">
            <Slider Name="slider"
                    Minimum="8"
                    Maximum="196"
                    Value="24" />
        </AppBar>
    </Page.TopAppBar>

    <Page.BottomAppBar>
        <AppBar Name="bottomAppBar">
            <StackPanel Orientation="Horizontal"
                        HorizontalAlignment="Right">

                <Button Content="Красный"
                        Foreground="Red"
                        Margin="24 12"
                        Click="OnAppBarButtonClick" />

                <Button Content="Зеленый"
                        Foreground="Green"
                        Margin="24 12"
                        Click="OnAppBarButtonClick" />

                <Button Content="Синий"
                        Foreground="Blue"
                        Margin="24 12"
                        Click="OnAppBarButtonClick" />
            </StackPanel>
        </AppBar>
    </Page.BottomAppBar>
</Page>

И снова элемент TextBlock располагается в центре экрана, но на этот раз его свойство FontSize привязано к элементу управления Slider, составляющему все содержимое верхней строки AppBar. Вторая строка AppBar задается свойству BottomAppBar и содержит горизонтальную панель StackPanel с тремя элементами управления Button, совместно использующими один обработчик Click в файле фонового кода:

private void OnAppBarButtonClick(object sender, RoutedEventArgs e)
{
     textBlock.Foreground = (sender as Button).Foreground;
}

Обычно работать со строкой приложения намного проще, чем с Popup или PopupMenu, потому что она является частью визуального дерева страницы; это упрощает настройку привязок и обработчиков событий. Единственное различие между элементами управления AppBar и элементами управления страницы заключается в том, что строки приложений обычно остаются невидимыми до тех пор, пока пользователь не проведет пальцем у верхнего или нижнего края экрана. После этого пользователь сможет взаимодействовать с находящимися на ней элементами управления:

Строка приложения

Цвет строки приложения и элементов управления определяется значением свойства RequestedTheme приложения, которому в этой программе задано значение Light.

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

Строка приложения автоматически исчезает и скрывается при щелчке или касании в любой точке за ее пределами или при нажатии клавиши Escape. Если вы предпочитаете, чтобы строка приложения не закрывалась подобным образом, задайте свойству IsSticky объекта AppBar значение true. В этом случае, чтобы убрать строку приложения, пользователь должен снова провести пальцем по экрану или же задать свойству IsOpen одного или обоих объектов AppBar значение false в файле фонового кода.

Иногда возникает необходимость закрыть строку приложения на программном уровне. Например, в этой конкретной программе для изменения цвета текста пользователь должен вызвать строку приложения движением пальца, а затем закрыть строку приложения другим движением или касанием за ее пределами. Однако строку приложений также можно закрыть из кода при нажатии кнопки:

private void OnAppBarButtonClick(object sender, RoutedEventArgs e)
{
    textBlock.Foreground = (sender as Button).Foreground;
    topAppBar.IsOpen = false;
    bottomAppBar.IsOpen = false;
}

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

В некоторых приложениях пользователь должен взаимодействовать со строкой приложения при первом запуске программы; в таких случаях свойство IsOpen инициализируется значением true. Как и Popup, класс AppBar содержит события Opened и Closed для инициализации и очистки.

Стили кнопок строки приложения

Многие приложения Windows 8 используют только нижнюю строку приложения с рядом круглых элементов управления Button. Кнопки обычно идентифицируются значком в круге и коротким текстом.

Основой для круглых кнопок является стиль, определенный в файле StandardStyles.xaml с ключом AppBarButtonStyle. Файл StandardStyles.xaml находится в папке Common каждого проекта С#, Visual Basic или С++ для Windows 8, создаваемого в Visual Studio. Файл включается в секцию Resources файла App.xaml, а следовательно, доступен для каждого приложения Windows 8. Если вы используете проект для Windows 8.1, то вы не найдете папку Common. В приложениях этого типа используется специальный элемент AppBarButton, имеющий встроенный стиль круглой кнопки.

AppBarButtonStyle содержит объект Setter, назначающий свойству FontFamily шрифт Segoe UI Symbol. Знак, выводимый на кнопке, является символом из этого шрифта. Как следует из названия, шрифт Segoe UI Symbol содержит знаки. Тем не менее это не классический знаковый шрифт, в котором знаки заменяют обычные буквы и цифры. В этом шрифте также присутствуют обычные символы и его можно использовать для обычных целей. Стандарт Юникод разрешает подобным шрифтам включать нестандартные символы, определяя диапазон кодов от 0xE000 до 0xF8FF как «область для приватного использования»; таким образом, символы в этом диапазоне специфичны для данного шрифта. Шрифт Segoe UI Symbol не заполняет всю область нестандартными символами, но диапазон от 0xE000 до 0xE1E9 содержит набор глифов, представляющих типичные компьютерные операции, а следовательно, подходящих для кнопок строки приложения.

В приложениях Windows 8.1 при использовании элемента AppBarButton, ему можно передать пользовательское значение в свойстве Icon, чтобы выбрать нужную иконку.

Например, если вы хотите разместить на строке приложения кнопку с изображением дома и словом "Домой", в приложении типа Windows 8 это делается так:

<Page.TopAppBar>
        <AppBar Name="topAppBar">
            <StackPanel Orientation="Horizontal">
                <Button Style="{StaticResource AppBarButtonStyle}"
                        Content="&#xE10F;"
                        AutomationProperties.Name="Home"
                        Click="Button_Click"/>
                
            </StackPanel>
        </AppBar>
</Page.TopAppBar>

А в приложении Windows 8.1:

<Page.TopAppBar>
        <AppBar Name="topAppBar">
            <StackPanel Orientation="Horizontal">
                <AppBarButton Icon="Home" Label="Домой"
                              Click="Button_Click" />                
            </StackPanel>
        </AppBar>
</Page.TopAppBar>

Атрибуты Content и Click вам уже знакомы. Класс AutomationProperties представляет собой коллекцию вложенных свойств, одним из которых является свойство Name. Эти свойства обычно используются для идентификации элементов пользовательского интерфейса в целях тестирования, а также для обеспечения работы вспомогательных технологий (например, экранных дикторов). Шаблон ControlTemplate, определенный в AppBarButtonStyle, использует свойство AutomationProperties.Name для отображения строки текста под кнопкой. Вот как эта конкретная кнопка выглядит с темной темой оформления:

Стиль кнопки AppBarButton

В приложении Windows 8.1 используется перечисление стандартных типов иконок для свойства Icon. Если вам нужно задать тип иконки, не входящий в данное перечисление, то можно использовать синтаксис вложенных свойств и явно задать свойство Icon используя объект FontIcon. Можно задать произвольное изображение, используя объект PathIcon и указав векторный путь в свойстве Data. Можно использовать также объект BitmapIcon и передать путь до статичного изображения. Все эти три подхода продемонстрированы в примере ниже:

...

<AppBarButton Label="Кнопка из шрифта" Click="Button_Click">
    <AppBarButton.Icon>
        <FontIcon FontFamily="Candara" Glyph="&#x03A3;"/>
    </AppBarButton.Icon>
</AppBarButton>

<AppBarButton Label="Кнопка из пути" Click="Button_Click">
    <AppBarButton.Icon>
        <PathIcon Data="F1 M 20,20L 24,10L 24,24L 5,24"/>
    </AppBarButton.Icon>
</AppBarButton>

<AppBarButton Label="BitmapIcon" Click="AppBarButton_Click">
    <AppBarButton.Icon>
        <BitmapIcon UriSource="ms-appx:///Assets/myicon.png"/>
    </AppBarButton.Icon>
</AppBarButton>
                    
...
Произвольный контент для кнопок AppBarButton

Было бы удобно получить полный список стилей кнопок строки приложения, определенных в StandardStyles.xaml, вместе со знаками и текстовыми надписями или значений перечисления для свойства Icon, если вы используете приложение для Windows 8.1. Вы можете найти этот список в статье "Стандартные стили и ресурсы", а также на сайте MSDN.

Давайте для удобства создадим программу, отображающую список всех стандартных иконок. Файл XAML содержит элементы ScrollViewer и StackPanel, готовые к заполнению, а также строку приложения с парой стандартных элементов управления RadioButton:

<Page ...>

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <ScrollViewer FontSize="32">
            <StackPanel x:Name="stackPanel" />
        </ScrollViewer>
    </Grid>

    <Page.BottomAppBar>
        <AppBar>
            <StackPanel Orientation="Horizontal">
                <RadioButton x:Name="valueSort"
                             Content="Сортировать по значению"
                             Checked="OnRadioButtonChecked" />
                
                <RadioButton x:Name="textSort"
                             Content="Сортировать по названию"
                             Checked="OnRadioButtonChecked" />
            </StackPanel>
        </AppBar>
    </Page.BottomAppBar>
</Page>

В конструкторе страницы файл фонового кода получает доступ к элементам перечисления Symbol и инициализирует пользовательскую коллекцию:

using System;
using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace WinRTTestApp
{
    public sealed partial class MainPage : Page
    {
        class Item
        {
            public Symbol Symbol;
            public string Name;
            public int Value;
        }

        List<Item> items = new List<Item>();

        public MainPage()
        {
            this.InitializeComponent();

            // Пройтись по перечислению Symbol и заполнить коллекцию items
            foreach (Symbol symbol in Enum.GetValues(typeof(Symbol)))
            {
                items.Add(new Item
                {
                    Symbol = symbol,
                    Name = Enum.GetName(typeof(Symbol), symbol),
                    Value = (int)symbol
                });
            }

            DisplayList();
        }

        private void DisplayList()
        {
            // Очистка StackPanel
            stackPanel.Children.Clear();

            foreach (Item item in items)
            {
                // StackPanel для каждого элемента данных
                StackPanel itemPanel = new StackPanel
                {
                    Orientation = Orientation.Horizontal,
                    Margin = new Thickness(0, 6, 0, 6)
                };

                // AppBarButton
                AppBarButton button = new AppBarButton
                {
                    Icon = new SymbolIcon(item.Symbol),
                    VerticalAlignment = VerticalAlignment.Center
                };
                itemPanel.Children.Add(button);

                // Значение
                TextBlock textBlock = new TextBlock
                {
                    Text = item.Value.ToString(),
                    FontSize = 28,
                    VerticalAlignment = VerticalAlignment.Center,
                    Margin = new Thickness(24, 0, 24, 0)
                };
                itemPanel.Children.Add(textBlock);

                // Название из перечисления
                textBlock = new TextBlock
                {
                    Text = item.Name,
                    FontSize = 28,
                    VerticalAlignment = VerticalAlignment.Center
                };
                itemPanel.Children.Add(textBlock);

                stackPanel.Children.Add(itemPanel);
            }
        }

        private void OnRadioButtonChecked(object sender, RoutedEventArgs e)
        {
            if (sender == valueSort)
            {
                // Сортировка по значению
                items.Sort((item1, item2) =>
                {
                    return item1.Symbol.CompareTo(item2.Symbol);
                });
            }
            else
            {
                // Сортировка по имени
                items.Sort((item1, item2) =>
                {
                    return item1.Name.CompareTo(item2.Name);
                });
            }

            // Закрытие строки приложения и вывод информации
            this.BottomAppBar.IsOpen = false;
            DisplayList();
        }
    }
}

На следующем рисунке изображена часть списка:

Список стандартных значений перечисления Symbol

Не ограничивайтесь изображениями из списка. Вы можете использовать любой символ шрифта Segoe UI Symbol для кнопок строки приложения или же выбрать другой шрифт.

Лучший чат для C# программистов