André Alves de Lima

Talking about Software Development and more…

Implementando FlyOuts de forma inteligente em aplicações para Windows Store com C#

Olá pessoal, tudo certo?

Depois de um tempão sem postar nenhum artigo técnico, estou de volta à ativa! O artigo de hoje aborda um conceito muito simples de aplicações para Windows Store (ou Metro Style Apps – não adianta a Microsoft insistir, esse nome pegou e pronto): a criação de FlyOuts. Você não sabe o que é FlyOut? Não tem problema, eu explico!

No aplicativo de e-mail do Windows 8, sabe quando você aproxima o mouse do canto direito superior da tela e a Charms Bar é exibida? Aí você clica, por exemplo, em Settings e logo depois em Accounts? Uma janela flutuante é exibida no canto direito da tela (com o nome “Accounts”), certo? Pois então, esse é um exemplo de FlyOut – um controle exibido logo em cima do controle de settings!


Se você estiver desenvolvendo um aplicativo para o Windows 8 utilizando JavaScript, é muito simples implementar um FlyOut. Basta utilizar o objeto SettingsFlyout e você consegue fazer isso de forma fácil, fácil. Nem vou mostrar por que já tem pronto na documentação e não tem nenhum segredo.

Agora, meu amigo, se você é um pobre desenvolvedor .NET e está desenvolvendo um aplicativo para Windows 8 utilizando C#, se prepare porque você vai ter que fazer uma puta gambiarra escrever um tanto considerável de código. Pelo que podemos ver no próprio fórum da MSDN americana, funcionários da Microsoft disseram que não deu tempo pra implementar essa funcionalidade nativamente. Fazer o quê? Pelo menos temos no próprio MSDN um exemplo já pronto mostrando como podemos contornar essa limitação e implementar o FlyOut por conta própria. O problema é que se você simplesmente copiar e colar o código do exemplo (que é bem extenso, como você pode ver), para cada FlyOut a ser exibido você vai ter que digitar (ou copiar e colar) muito código. E isso não é o que nós queremos, certo?

Pois bem, é para isso que estamos aqui. Quando eu e o Pedro Castelo trabalhamos no Bubble Brain 360 (um divertido joguinho estilo Bubble Break que utiliza o acelerômetro do seu dispositivo para deixa-lo mais divertido – baixe aqui agora mesmo!), nós tivemos que criar mais de um FlyOut no jogo. Vendo a quantidade necessária de código, não pensamos duas vezes senão criar uma classe para nos ajudar nesse processo. E é uma versão simplificada dessa classe da biblioteca do brain4dev que vou compartilhar neste artigo!

(Download do código completo aqui)

Antes de tudo, para mostrar um FlyOut, a primeira coisa que temos que fazer é criar o FlyOut em si. Isso não dá pra fugir. Porém, o que você não precisa do código do exemplo da MSDN é aquele estilo gigantesco para o botão “voltar” da página de Settings. Dá pra fazer um muito mais simples herdando do estilo SnappedBackButtonStyle já existente.

Então, vamos começar. Partindo do pressuposto de que você já criou um novo projeto Windows Store Blank App (XAML), adicione um novo UserControl chamado AboutControl a esse projeto e utilize o código a seguir:

<UserControl
    x:Class="FlyOutSample.AboutControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:FlyOutSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="600"
    d:DesignWidth="346">

    <Border BorderBrush="Black" BorderThickness="1,0,0,0">
        <Grid Background="Black">
            <Grid.RowDefinitions>
                <RowDefinition Height="80"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <Grid Grid.Row="0">
                <Grid Margin="40,32,17,13">
                    <Grid.Transitions>
                        <TransitionCollection>
                            <EntranceThemeTransition FromHorizontalOffset="50" />
                        </TransitionCollection>
                    </Grid.Transitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="30" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <Button Grid.Column="0" Click="BackButton_Clicked" Style="{StaticResource SettingsBackButtonStyle}" HorizontalAlignment="Left" Grid.ColumnSpan="2" />
                    <TextBlock Margin="10,0,0,0" Grid.Column="1" FontFamily="Segoe UI" FontWeight="SemiLight" FontSize="24.6667" Text="About my app" HorizontalAlignment="Left" />
                </Grid>
            </Grid>
        </Grid>
    </Border>
</UserControl>

Algumas partes desse código servem para deixar o UserControl com cara de FlyOut. Por exemplo, nós configuramos as propriedades DesignHeight em 600 e DesignWidth em 346 (essa propriedade é importante para você conseguir sentir melhor como vai ficar o seu FlyOut, uma vez que todo FlyOut tem 346 pixels de largura). Além disso, nós alteramos o LayoutRoot para uma Border, ao invés de um Grid (da mesma forma como mostra o exemplo da Microsoft). Dentro da Border, temos um Grid com duas Rows, sendo que a primeira contém o título do seu FlyOut e o botão de voltar. A segunda Row do Grid serviria para você colocar o conteúdo em si do seu FlyOut (mas esse não é o foco deste artigo, então, deixamos em branco).

Se você tentar compilar o projeto agora, pode ser que ele compile, já que o XAML não é tão rigoroso em tempo de compilação, deixando para falar que não encontrou um estilo só em tempo de execução (odeio isso, by the way). Porém, na realidade ainda faltam dois detalhes relacionados a esse controle: o estilo SettingsBackButtonStyle e a implementação do event handler BackButton_Clicked.

First things first, então, vamos primeiro adicionar o estilo SettingsBackButtonStyle. Para facilitar, vamos adicionar no próprio arquivo StandardStyles.xaml, que você pode encontrar dentro da pasta Common no seu projeto. Nesse arquivo, adicione o seguinte estilo:

    <Style x:Key="SettingsBackButtonStyle" TargetType="Button" BasedOn="{StaticResource SnappedBackButtonStyle}">
        <Setter Property="Margin" Value="3,0,-7,-33"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
    </Style>

Bem menor do que o código linguiça do exemplo da MSDN, né? Enfim, a segunda coisa a fazer é abrir o code behind do seu AboutControl (ou seja, no arquivo AboutControl.cs) e adicionar o event handler BackButton_Clicked, que basicamente serve para fechar o FlyOut e mostrar a janela de Settings ao clicar no botão de voltar:

        private void BackButton_Clicked(object sender, RoutedEventArgs e)
        {
            if (this.Parent is Popup)
                ((Popup)this.Parent).IsOpen = false;
            Windows.UI.ApplicationSettings.SettingsPane.Show();
        }

Finalmente, é hora de abordarmos o que realmente interessa, que é a exibição desse FlyOut. No código de exemplo da MSDN (veja a seção “Assign the settings Flyout to the app commands collection”), temos um tanto considerável de código que seria necessário a cada vez que você queira exibir um FlyOut. Simplifiquemos esse código criando a classe FlyOutHelper! Para isso, adicione uma nova classe no seu projeto, chamada FlyOutHelper e utilize o seguinte código:

    public static class FlyOutHelper
    {
        public const double _settingsWidth = 346;
        public static Windows.UI.Xaml.Controls.Primitives.Popup _settingsPopup;

        public static Windows.UI.Popups.UICommandInvokedHandler SetupFlyOut<USERCONTROLTYPE>()
            where USERCONTROLTYPE : Windows.UI.Xaml.Controls.UserControl
        {
            return (uiCommand) =>
            {
                _settingsPopup = new Windows.UI.Xaml.Controls.Primitives.Popup();
                _settingsPopup.Closed += OnFlyOutPopupClosed;
                Windows.UI.Xaml.Window.Current.Activated += OnFlyOutActivated;
                _settingsPopup.IsLightDismissEnabled = true;
                _settingsPopup.Width = _settingsWidth;
                _settingsPopup.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;

                USERCONTROLTYPE myPane = (USERCONTROLTYPE)Activator.CreateInstance(typeof(USERCONTROLTYPE));

                myPane.Width = _settingsWidth;
                myPane.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;

                _settingsPopup.Child = myPane;
                _settingsPopup.SetValue(Windows.UI.Xaml.Controls.Canvas.LeftProperty, Windows.UI.Xaml.Window.Current.Bounds.Width - _settingsWidth);
                _settingsPopup.SetValue(Windows.UI.Xaml.Controls.Canvas.TopProperty, 0);
                _settingsPopup.IsOpen = true;
            };
        }

        private static void OnFlyOutActivated(object sender, Windows.UI.Core.WindowActivatedEventArgs e)
        {
            if (e.WindowActivationState == Windows.UI.Core.CoreWindowActivationState.Deactivated)
                _settingsPopup.IsOpen = false;
        }

        private static void OnFlyOutPopupClosed(object sender, object e)
        {
            Windows.UI.Xaml.Window.Current.Activated -= OnFlyOutActivated;
        }
    }

Basicamente essa classe encapsula toda a complexidade e repetição do código exemplo da MSDN e possibilita que você exiba um FlyOut indicando apenas uma informação: o tipo do FlyOut (no nosso caso AboutControl). Ele é muito parecido com o código da Microsoft, porém, utilizando generics nós conseguimos instanciar o FlyOut utilizando o tipo que foi fornecido na chamada. Legal, não?

Para utilizar o FlyOutHelper, vamos no code behind da nossa MainPage e adicionemos o seguinte código:

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

            Windows.UI.ApplicationSettings.SettingsCommand command = new Windows.UI.ApplicationSettings.SettingsCommand("AboutPage", "About", FlyOutHelper.SetupFlyOut<AboutControl>());
            args.Request.ApplicationCommands.Add(command);
        }

E, para finalizar, adicione o hook do evento CommandsRequested no construtor da MainPage:

        public MainPage()
        {
            this.InitializeComponent();
            Windows.UI.ApplicationSettings.SettingsPane.GetForCurrentView().CommandsRequested += Settings_CommandsRequested;
        }

Pronto! Execute a aplicação, abra a charms bar, clique em Settings e depois em About, e então veja nosso AboutControl sendo exibido em forma de FlyOut!


Bom pessoal, era isso que eu queria mostrar no artigo de hoje. Em breve espero fazer duas versões em vídeo desse artigo (pt-br e en-us). Assim que eu fizer, atualizo este mesmo post com os links.

Espero que tenham gostado. Até a próxima!

André Lima

One thought on “Implementando FlyOuts de forma inteligente em aplicações para Windows Store com C#

Deixe uma resposta

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