André Alves de Lima

Talking about Software Development and more…

Exibindo as mesmas settings em todas as páginas de uma Windows Store App com C#

Fala galera, tudo beleza?

Estou de volta com mais um artigo abordando o assunto desenvolvimento de aplicações para a Windows Store do Windows 8 (ou aplicativos Metro, como são mais conhecidos). No artigo anterior abordei a questão de FlyOuts e, no artigo de hoje, vou abordar mais um assunto relacionado à Settings Pane.

Imagine que você tem um aplicativo para a Windows Store e esse aplicativo possui várias páginas (uma situação bem comum, não?). Agora imagine que você quer apresentar, em todas as páginas do seu aplicativo, as mesmas opções na Settings Pane. Como você faria?


Bom, para começarmos a conversar melhor sobre esse assunto, vamos ver como conseguimos mostrar duas opções na Settings Pane de uma página qualquer. Para entender melhor como fazer isso, você pode das uma olhada neste exemplo da MSDN. Ou, se preferir algo mais simplificado, vamos construir um exemplo agora.

Como este artigo demanda um aplicativo com múltiplas páginas, vamos começar criando um novo projeto escolhendo o template de Windows Store Grid App. Ao criar um projeto utilizando esse template, três páginas são automaticamente criadas no novo projeto: GroupedItemsPage, GroupDetailPage e ItemDetailPage. Abra o code behind (arquivo .cs) da página GroupedItemsPage (que é a página inicial da aplicação) e adicione o seguinte event handler:

        void BasePage_CommandsRequested(Windows.UI.ApplicationSettings.SettingsPane sender, Windows.UI.ApplicationSettings.SettingsPaneCommandsRequestedEventArgs args)
        {
            args.Request.ApplicationCommands.Clear();

            Windows.UI.ApplicationSettings.SettingsCommand command1 = new Windows.UI.ApplicationSettings.SettingsCommand("HomePage", "Andre's blog",
                async (x) => await Windows.System.Launcher.LaunchUriAsync(new Uri("http://www.andrealveslima.com.br")));
            Windows.UI.ApplicationSettings.SettingsCommand command2 = new Windows.UI.ApplicationSettings.SettingsCommand("brain4dev", "brain4dev",
                async (x) => await Windows.System.Launcher.LaunchUriAsync(new Uri("http://www.brain4dev.com")));

            args.Request.ApplicationCommands.Add(command1);
            args.Request.ApplicationCommands.Add(command2);
        }

Além disso, vá até o construtor dessa classe e adicione a linha para tratar o evento CommandsRequested, que é disparado logo antes da Settings Pane ser aberta:

        public GroupedItemsPage()
        {
            this.InitializeComponent();
            // Linha adicionada para exibir os itens na Settings Pane:
            Windows.UI.ApplicationSettings.SettingsPane.GetForCurrentView().CommandsRequested += BasePage_CommandsRequested;
        }

Execute a aplicação, abra a Settings Pane e veja que os dois itens foram adicionados corretamente:


Mas, e agora? Como fazemos para que exatamente os mesmos itens sejam exibidos na Settings Pane das outras páginas dessa aplicação? Dentre algumas possibilidades, neste artigo quero destacar três modos de se realizar essa tarefa.

Possibilidade 1: CTRL + C / CTRL + V

O primeiro, mais fácil e pior modo de conseguir mostrar as mesmas settings nas Settings Pane de todas as páginas da sua aplicação é utilizar o famoso (e inimigo de todo bom programador) CTRL + C / CTRL + V. É só aplicar a mesma ideia que apresentei acima em todas as páginas da sua aplicação, replicando o event handler e colocando o hook para o evento CommandsRequested no construtor de todas elas.

Obviamente não recomendo que ninguém utilize esse método, uma vez que você teria que sair alterando o mesmo código em inúmeros lugares caso queira alterar algo.

Possibilidade 2: Compartilhando o event handler

A segunda possibilidade, apesar de não ser a ideal, é consideravelmente melhor que a primeira. A ideia é compartilhar o mesmo event handler entre todas as páginas. Dessa forma, restaria apenas hookar o evento em cada página da nossa aplicação.

Para isso, precisamos transformar o event handler
BasePage_CommandsRequested em public
static e colocá-lo em um lugar de fácil compartilhamento. Um bom lugar para isso seria na classe App. Dessa forma, recorte o event handler
BasePage_CommandsRequested da classe GroupedItemsPage e cole esse handler no code behind da classe App, alterando-o também para public
static:

        public static void BasePage_CommandsRequested(Windows.UI.ApplicationSettings.SettingsPane sender, Windows.UI.ApplicationSettings.SettingsPaneCommandsRequestedEventArgs args)
        {
            args.Request.ApplicationCommands.Clear();

            Windows.UI.ApplicationSettings.SettingsCommand command1 = new Windows.UI.ApplicationSettings.SettingsCommand("HomePage", "Andre's blog",
                async (x) => await Windows.System.Launcher.LaunchUriAsync(new Uri("http://www.andrealveslima.com.br")));
            Windows.UI.ApplicationSettings.SettingsCommand command2 = new Windows.UI.ApplicationSettings.SettingsCommand("brain4dev", "brain4dev",
                async (x) => await Windows.System.Launcher.LaunchUriAsync(new Uri("http://www.brain4dev.com")));

            args.Request.ApplicationCommands.Add(command1);
            args.Request.ApplicationCommands.Add(command2);
        }

E então, em cada uma de suas páginas você teria que fazer um hook do evento CommandsRequested apontando para o handler que está na classe App. Veja como ficaria, por exemplo, na página GroupedItemsPage:

        public GroupedItemsPage()
        {
            this.InitializeComponent();
            // Linha adicionada para exibir os itens na Settings Pane. Repare que estamos utilizando o handler que está na classe App:
            Windows.UI.ApplicationSettings.SettingsPane.GetForCurrentView().CommandsRequested += App.BasePage_CommandsRequested;
        }

Essa é uma boa saída para quem não tem a possibilidade de alterar a aplicação para utilizar o terceiro método que quero mostrar a seguir.

Possibilidade 3: Crie uma página base!

A terceira e mais indicada maneira de realizarmos essa tarefa é criarmos uma página base, e colocar nessa página o código para gerenciar a Settings Pane. Nessa página base poderíamos adicionar diversos outros tratamentos caso necessário. Vamos então adicionar uma nova classe para ser a página base na nossa aplicação, chamada de BasePage. Essa classe deve herdar de LayoutAwarePage e deve conter exatamente o código para exibir os nossos itens na Settings Pane:

    public class BasePage : GlobalSettings.Common.LayoutAwarePage
    {
        public BasePage()
        {
            Windows.UI.ApplicationSettings.SettingsPane.GetForCurrentView().CommandsRequested += BasePage_CommandsRequested;
        }

        void BasePage_CommandsRequested(Windows.UI.ApplicationSettings.SettingsPane sender, Windows.UI.ApplicationSettings.SettingsPaneCommandsRequestedEventArgs args)
        {
            args.Request.ApplicationCommands.Clear();

            Windows.UI.ApplicationSettings.SettingsCommand command1 = new Windows.UI.ApplicationSettings.SettingsCommand("HomePage", "Andre's blog",
                async (x) => await Windows.System.Launcher.LaunchUriAsync(new Uri("http://www.andrealveslima.com.br")));
            Windows.UI.ApplicationSettings.SettingsCommand command2 = new Windows.UI.ApplicationSettings.SettingsCommand("brain4dev", "brain4dev",
                async (x) => await Windows.System.Launcher.LaunchUriAsync(new Uri("http://www.brain4dev.com")));

            args.Request.ApplicationCommands.Add(command1);
            args.Request.ApplicationCommands.Add(command2);
        }
    }

Finalmente, agora que já temos nossa página base, basta trocarmos a informação da página base em todas as páginas do nosso projeto (GroupedItemsPage, GroupDetailPage e ItemDetailPage), de forma que elas herdem da nossa nova BasePage. Para fazer isso, precisamos alterar dois lugares. O primeiro deles é o XAML, onde ao invés das páginas herdarem de common:LayoutAwarePage, devem herdar de local:BasePage.

Confira o antes:

<common:LayoutAwarePage
    x:Name="pageRoot"
    x:Class="GlobalSettings.GroupedItemsPage"
    DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:GlobalSettings"
    xmlns:data="using:GlobalSettings.Data"
    xmlns:common="using:GlobalSettings.Common"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <!-- Resto do código da página -->

</common:LayoutAwarePage>

E o depois:

<local:BasePage
    x:Name="pageRoot"
    x:Class="GlobalSettings.GroupedItemsPage"
    DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:GlobalSettings"
    xmlns:data="using:GlobalSettings.Data"
    xmlns:common="using:GlobalSettings.Common"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <!-- Resto do código da página -->

</local:BasePage>

E também temos que alterar no code behind, onde ao invés de herdarmos de Common.LayoutAwarePage, temos que herdar de BasePage.

Confira o antes:

    public sealed partial class GroupedItemsPage : Common.LayoutAwarePage
    {
        /* Resto do código da página */
    }

E o depois:

    public sealed partial class GroupedItemsPage : BasePage
    {
        /* Resto do código da página */
    }

Pronto! Faça essas alterações em todas as páginas do projeto e você terá os itens na Settings Pane de todas elas. Simples e elegante, não?

É isso aí, espero que vocês tenham gostado. O código de exemplo na MSDN Code Gallery está disponível aqui. Se possível gravarei um vídeo com o conteúdo deste artigo. Assim que fizer, volto aqui e edito o post adicionando esses conteúdos.

Até a próxima!

André Lima

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *