воскресенье, 30 сентября 2012 г.

Контракты в Windows 8 приложениях (Settings)

Еще по лету, я публиковал статью "Хранение настроек в Windows 8 приложениях". Ну а сегодня посмотрим пример, как сделать настройку нашего приложения через контракт Settings.

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

<Page
    x:Class="SettingsExample.MainPage"
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:local="using:SettingsExample"
    xmlns:d=http://schemas.microsoft.com/expression/blend/2008
    xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
    mc:Ignorable="d">

    <Grid x:Name="grMain">
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
        <Rectangle x:Name="rc1" Margin="40,40,40,20" />
        <Rectangle Grid.Row="1" x:Name="rc2" Margin="40,20,40,40" />
    </Grid>
</Page>

Ну и в коде, пишем метод считывающий настройки и применяющий их к прямоугольникам и фону:

///
/// Массив цветов, которые можно применять к нашим элементам
///
static Color[] _colors = { Colors.Red, Colors.Green, Colors.Yellow, Colors.Blue, Colors.Magenta, Colors.Orange, Colors.Black };

private void ApplySettings()
{
    ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
    int gridColorIndex = localSettings.Values["grid"] != null ? (int)localSettings.Values["grid"] : 6;
    grMain.Background = new SolidColorBrush(_colors[gridColorIndex]);
    int rect1ColorIndex = localSettings.Values["rect1"] != null ? (int)localSettings.Values["rect1"] : 0;
    rc1.Fill = new SolidColorBrush(_colors[rect1ColorIndex]);
    int rect2ColorIndex = localSettings.Values["rect2"] != null ? (int)localSettings.Values["rect2"] : 1;
    rc2.Fill = new SolidColorBrush(_colors[rect2ColorIndex]);
}

Все, вызываем означенный метод, при переходе на главную страницу:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    ApplySettings();
}
Для начала, давайте запустим и посмотрим как выглядит панель настроек для такого приложения:

Пока, у нашего приложения есть целый 1 пункт, в котором можно посмотреть какие права предоставлены нашему приложению.
Давайте добавим еще один пункт, который будет менять по кругу (из нашего массива цветов) цвет фона.
Для этого, необходимо подписаться на событие  CommandsRequested нашего текущего отображения, а в обработчике, определить, какие команды мы будем добавлять:

void MainPage_CommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)

{

        UICommandInvokedHandler handler = new UICommandInvokedHandler(onSettingsCommand);

        SettingsCommand generalCommand = new SettingsCommand("nextBackgrounColor", "Следующий цвет фона", handler);
        args.Request.ApplicationCommands.Add(generalCommand);
}

Здесь, onSettingCommand - метод который будет вызываться при выборе команды, "nextBackgrounColor" - метка команды. Хорошо, пишем обработчик команды:

private void onSettingsCommand(IUICommand command)
{
    ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
    int gridColorIndex = localSettings.Values["grid"] != null ? (int)localSettings.Values["grid"] : 6;
    gridColorIndex++;
    if (gridColorIndex == _colors.Length)
    {
        gridColorIndex = 0;
    }
    localSettings.Values["grid"] = gridColorIndex;
    ApplySettings();
}

Теперь, можем запустить приложение и убедимся, что наше приложение в настройках обзавелось новым пунктом, при выборе которого меняется цвет фона:
Я бы хотел обратить внимание, на два момента:
1. Настройки в Windows 8 приложениях принято менять сразу, не дожидаясь нажатия кнопок принять или перезапуска приложения.
2. Метод, подписанный на событие CommandsRequested будет вызываться каждый раз, когда пользователь будет открывать панель настроек, что позволяет нам показывать разные настройки, например в зависимости от выбранного элемента управления на странице.

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

<Page
    x:Class="SettingsExample.SettingsPage"
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:local="using:SettingsExample"
    xmlns:d=http://schemas.microsoft.com/expression/blend/2008
    xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
    mc:Ignorable="d">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="Margin" Value="5" />
            </Style>
            <Style TargetType="ComboBox">
                <Setter Property="Margin" Value="5" />
                <Setter Property="ItemTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <Rectangle Height="20" Width="200" >
                                <Rectangle.Fill>
                                    <SolidColorBrush Color="{Binding }"/>
                                </Rectangle.Fill>
                            </Rectangle>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>
        <TextBlock Text="Цвет фона" Grid.Row="0" />
        <ComboBox x:Name="cbGrid" Grid.Row="1" />
        <TextBlock Text="Цвет верхнего прямоугольника" Grid.Row="2" />
        <ComboBox x:Name="cbRect1" Grid.Row="3" />
        <TextBlock Text="Цвет нижнего прямоугольника" Grid.Row="4" />
        <ComboBox x:Name="cbRect2" Grid.Row="5" />
    </Grid>
</Page>
Ну и немножко поправим конструктор, добавив событие, которым наша форма настроек будет уведомлять главную о изменении цветов:

public sealed partial class SettingsPage : Page
{
    public SettingsPage(Color[] colors, Color gridColor, Color rect1Color, Color rect2Color)
    {
        this.InitializeComponent();
        cbGrid.ItemsSource = colors;
        cbGrid.SelectedItem = gridColor;
        cbGrid.SelectionChanged += (s, e) => OnColorChanged("grid", cbGrid.SelectedIndex);
        cbRect1.ItemsSource = colors;
        cbRect1.SelectedItem = rect1Color;
        cbRect1.SelectionChanged += (s, e) => OnColorChanged("rect1", cbRect1.SelectedIndex);
        cbRect2.ItemsSource = colors;
        cbRect2.SelectedItem = rect2Color;
        cbRect2.SelectionChanged += (s, e) => OnColorChanged("rect2", cbRect2.SelectedIndex);
    }

    public event Action<string, int> ColorChanged;

    private void OnColorChanged(string element, int colorIndex)
    {
        var handler = ColorChanged;
        if (handler != null)
        {
            handler(element, colorIndex);
        }
    }
 
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    }
}

Все, правим главную форму. Немного изменим добавление команд:

void MainPage_CommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
        UICommandInvokedHandler handler = new UICommandInvokedHandler(onSettingsCommand);
        SettingsCommand generalCommand = new SettingsCommand("changeColors", "Настроить цвета", handler);
        args.Request.ApplicationCommands.Add(generalCommand);
}

Также поправим обработчик команды:

private void onSettingsCommand(IUICommand command)
{
    // Создаем и настраиваем высплывающее окно
    var configPopup = new Popup();
    configPopup.IsLightDismissEnabled = true;
    configPopup.Width = 200;
    configPopup.Height = Window.Current.Bounds.Height;
    configPopup.ChildTransitions = new TransitionCollection();
    configPopup.ChildTransitions.Add(new PaneThemeTransition()
    {
        Edge = (SettingsPane.Edge == SettingsEdgeLocation.Right) ?
                EdgeTransitionLocation.Right :
                EdgeTransitionLocation.Left
    });
    // Создаем страницу с настройками
    SettingsPage settingsPage =
        new SettingsPage(
            _colors,
            ((SolidColorBrush)grMain.Background).Color,
            ((SolidColorBrush)rc1.Fill).Color,
            ((SolidColorBrush)rc2.Fill).Color);
    settingsPage.Width = configPopup.Width;
    settingsPage.Height = configPopup.Height;
    settingsPage.ColorChanged += settingsPage_ColorChanged;
    configPopup.Child = settingsPage;
    configPopup.SetValue(Canvas.LeftProperty, SettingsPane.Edge == SettingsEdgeLocation.Right ? (Window.Current.Bounds.Width - configPopup.Width) : 0);
    configPopup.SetValue(Canvas.TopProperty, 0);
    // Показываем окно с настройками
    configPopup.IsOpen = true;
}

Ну и последнее, метод, который будет вызываться при вызове события изменения цвета в окне настроек:

void settingsPage_ColorChanged(string element, int colorIndex)
{
    ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
    localSettings.Values[element] = colorIndex;
    ApplySettings();
}

Ну и вот так это будет выглядеть в процессе работы:
 
 
На этом все.

Комментариев нет:

Отправить комментарий