André Alves de Lima

Talking about Software Development and more…

Utilizando APIs do WinRT em aplicações desktop

Já faz um tempo que eu venho postando conteúdo relacionado ao WinRT (plataforma de aplicativos “modernos” para o Windows 8.x). Basta conferir a categoria WinRT aqui do meu blog e você verá que eu venho abordando esse tema basicamente desde que o Windows 8 foi disponibilizado para o público, em Outubro de 2012 (nossa, como o tempo passa rápido!). Porém, pelo menos na minha percepção, essa plataforma ainda não “pegou” (quem sabe com as mudanças no Windows 10 ela finalmente deslanche?). Claro que existem muitos aplicativos desenvolvidos para a interface moderna do Windows 8, mas, principalmente no meio empresarial, poucas empresas mergulharam a fundo no WinRT. É devido a esse fato que eu resolvi escrever essa semana sobre a utilização das APIs do WinRT em aplicações desktop (WPF ou Windows Forms).

Imagine que você tem um aplicativo WPF ou Windows Forms. Imagine também que você não quer criar uma versão desse aplicativo para a interface “moderna” do Windows 8, porque:

  • Não acho que um aplicativo WinRT faria sentido ou traria algum benefício para o meu negócio;
  • Acho que a plataforma WinRT é muito difícil de utilizar / a curva de aprendizado é muito grande (triste realidade para programadores Windows Forms que ainda não se aventuraram com o WPF);
  • A Windows Store é irrelevante para mim;
  • Acho que o WinRT não “pegou” e quero esperar para ver o que vai acontecer com essa plataforma antes de investir meu tempo com ela;
  • Todas as alternativas acima

Porém, ao mesmo tempo, você pensa que seria bem legal utilizar alguns recursos do WinRT na sua aplicação desktop. Que tal exibir uma “toast notification” através do seu aplicativo Windows Forms (ou WPF)?

Pois isso é o que vamos aprender no artigo de hoje. Baseado no exemplo oficial da Microsoft (que, a propósito, não funciona) e num outro artigo sobre o mesmo tema (que também não funciona mais nos dias de hoje), resolvi fazer um passo-a-passo para que você entenda como utilizar algumas das APIs do WinRT em aplicações desktop.

Quais APIs do WinRT eu posso utilizar em aplicações desktop?

Uma das formas de descobrir quais APIs do WinRT estão disponíveis para aplicações desktop é conferir a documentação. Na seção “Requirements” da documentação, em todas as classes do WinRT você consegue identificar se a classe é suportada em aplicações desktop ou não. Por exemplo, veja a seção de “Requirements” da classe MediaCapture (que é uma das classes suportadas em aplicações desktop):

Obviamente dá um trabalhão verificar cada classe para ver se ela é compatível ou não com aplicações desktop. Mas, como sempre, um doidão que trabalha na Microsoft desenvolveu uma ferramenta que lista os tipos do WinRT que são compatíveis com aplicações desktop: a DualApi Finder.

Baixe a ferramenta, execute, selecione o diretório “C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral\“, clique “Go!” e eis que você verá a lista de APIs compatíveis com aplicações desktop:

Repare que tem muita coisa interessante que pode ser utilizada, incluindo todos os sensores, como acelerômetro, giroscópio, sensor de luminosidade, etc.

Criando um projeto desktop com suporte às APIs do WinRT

Como mencionei anteriormente, é possível utilizar a lista de APIs que vimos na seção acima em aplicações Windows Forms ou WPF, desde que o projeto esteja utilizando a versão 4.5 do .NET Framework e desde que a aplicação seja executada em um computador com Windows 8.1 ou superior. Utilizarei WPF no exemplo desse artigo, mas, você poderia muito bem utilizar um projeto Windows Forms e ele funcionaria da mesma maneira (eu testei e funcionou).

A primeira ação que devemos realizar após criar o projeto é descarrega-lo, pois teremos que alterar o arquivo “csproj” para adicionar o suporte às APIs do WinRT. Para isso, clique com o botão direito no projeto e escolha a opção “Unload Project“:

Feito isso, clique novamente com o botão direito no projeto e escolha a opção “Edit xxxx.csproj” (onde “xxxx” é o nome do seu projeto):

No xml do nosso arquivo “csproj“, temos que adicionar a seguinte linha dentro da primeira tagPropertyGroup“:

    <TargetPlatformVersion>8.1</TargetPlatformVersion>

Salve o “csproj“, feche-o e recarregue-o clicando com o botão direito no projeto e escolhendo a opção “Reload Project“:

Após realizarmos essas etapas, conseguiremos adicionar a referência às APIs do WinRT. Para isso, clique com o botão direito em “References” e escolha a opção “Add Reference“. Na janela “Reference Manager” vá até o nó “Windows 8.1“, marque a referência ao item denominado “Windows” e clique em “OK“:

Com isso adicionamos a referência à API do WinRT no nosso projeto WPF. Porém, precisamos adicionar outras três referências para que a nossa aplicação compile com sucesso. Portanto, escolha a opção “Add Reference” novamente e, na janela “Reference Manager“, clique em “Browse” e encontre às dllsSystem.Runtime.dll“, “System.Runtime.InteropServices.WindowsRuntime.dll” e “System.Runtime.WindowsRuntime.dll” dentro do diretório do .NET Framework:

Uma vez adicionadas essas referências, estamos prontos para utilizar qualquer uma daquelas APIs do WinRT em aplicativos desktop.

Exibindo toast notifications em aplicações desktop

A API que eu escolhi demonstrar nesse artigo foi a de “toast notifications“. O namespace que contém as classes responsáveis por esse tipo de notificação é o “Windows.UI.Notifications“, que é um dos namespaces suportados também em aplicações desktop. Caso você queira primeiro entender como exibir notificações em aplicativos para a Windows Store, confira este artigo.

Vamos começar definindo a UI do nosso exemplo. Adicione dois TextBlocks, dois TextBoxes e um Button na MainWindow de forma que fique parecido com a imagem abaixo:

Segue o XAML:

    <Grid>
        <StackPanel Margin="30"
                    Orientation="Vertical">
            <TextBlock Text="Primeira linha:" />
            <TextBox x:Name="PrimeiraLinhaTextBox" />
            <TextBlock Text="Segunda linha:" />
            <TextBox x:Name="SegundaLinhaTextBox" />
            <Button x:Name="ExibirToastButton"
                    Content="Exibir toast notification"
                    Click="ExibirToastButton_Click" />
        </StackPanel>
    </Grid>

Agora vamos até o code-behind adicionar o código que será executado ao clicarmos no botão:

        private void ExibirToastButton_Click(object sender, RoutedEventArgs e)
        {
            var notifier = Windows.UI.Notifications.ToastNotificationManager.CreateToastNotifier();
            string templateText =
                "<toast>" +
                "   <visual>" +
                "      <binding template=\"ToastText02\">" +
                "         <text id=\"1\">" + PrimeiraLinhaTextBox.Text + "</text>" +
                "         <text id=\"2\">" + SegundaLinhaTextBox.Text + "</text>" +
                "      </binding>" +
                "   </visual>" +
                "</toast>";
            var template = new Windows.Data.Xml.Dom.XmlDocument();
            template.LoadXml(templateText);
            var notification = new Windows.UI.Notifications.ToastNotification(template);
            notifier.Show(notification);
        }

Repare que o processo de exibição de toasts é muito simples. Basta criar uma instância de ToastNotifier (através do método CreateToastNotifier), carregar o template (que é um XML) dentro de um XmlDocument, criar uma ToastNotification passando o template no construtor (veja os XMLs dos templates disponíveis neste link) e chamar o método “Show” do ToastNotifier passando a ToastNotification.

Se executarmos esse código em uma aplicação para a Windows Store, a toast notification seria exibida normalmente. Porém, se executarmos a nossa aplicação desktop e clicarmos no botão “Exibir toast notification“, ela não funcionará. Pior ainda, uma exception será lançada:

Por que isso acontece? Porque alguém muito inteligente na Microsoft decidiu que só é possível exibir toast notifications através de um aplicativo se ele tiver um link criado na página inicial (não precisa ser um link “pinnado” na página inicial, basta ele estar ao menos “instalado” na página inicial). Quero acreditar que exista um bom motivo por trás dessa limitação, mas, sinceramente, não consegui encontrar a razão disso até agora.

Enfim, a solução é “instalar” o nosso aplicativo na página inicial, via código. Para isso, utilizamos uma classe utilitária que peguei e adaptei deste exemplo da Microsoft. Baixe este arquivo zip, descompacte o arquivo ShortcutHelper.cs que está dentro dele na mesma pasta do seu projeto e adicione o arquivo ao seu projeto.

Uma vez adicionada a classe ShortcutHelper ao projeto, tente compilar a solução e veja que você receberá uma quantidade significativa de erros de compilação:

Isso acontece porque essa classe ShortcutHelper necessita do “Windows API Code Pack for Microsoft .NET Framework“, que infelizmente não está mais disponível para download, mas, felizmente está disponível no NuGet. Instale, então, através do NuGet, o pacote chamado “Microsoft.WindowsAPICodePack-Shell” e tente compilar novamente (para saber mais informações sobre como adicionar pacotes vindos do NuGet no seu projeto, confira este artigo). Dessa vez o projeto deve compilar com sucesso.

Agora que o nosso projeto está compilando novamente, vamos ajustá-lo de forma que ele utilize a classe ShortcutHelper para “instalar” o aplicativo na tela inicial e fazer com que a nossa toast notification seja finalmente exibida. Para isso, vá novamente até o code-behind da MainWindow, crie um atributo do tipo string chamado “_appId” e chame o método TryCreateShortcut da classe ShortcutHelper, passando o “_appId“. Você pode escolher livremente o conteúdo de “_appId“, mas, você deve se atentar de que esse será o nome utilizado no link criado na página inicial. Eu escolhi “ExemploToastWPF“:

        private string _appId = "ExemploToastWPF";

        public MainWindow()
        {
            InitializeComponent();
            ShortcutHelper.ShortcutHelper.TryCreateShortcut(_appId);
        }

Outro pequeno detalhe que precisamos alterar é que, no clique do nosso botão, ao criarmos a instância de ToastNotifier, devemos passar a “_appId” como parâmetro:

            var notifier = Windows.UI.Notifications.ToastNotificationManager.CreateToastNotifier(_appId);

Pronto! Execute a aplicação, preencha os Textboxes com algum texto, clique no botão “Exibir toast notification” e veja que a toast notification é exibida:

Note também que um atalho foi criado na seção de “Apps” da tela inicial:

Para removê-lo, clique com o botão direito no atalho, escolha a opção “Open file location” e delete o link. Mas, lembre-se que ele será criado novamente da próxima vez que você executar a aplicação.

Caso você queira exibir toast notifications mais elaborados (com imagens, por exemplo), confira a lista de templates disponíveis para toast notifications. Eu testei os templates com imagens, mas, eles infelizmente não funcionaram com uma imagem vinda de uma URL. O template com imagem só funcionou com uma imagem armazenada em disco e utilizando o source no formato “file:///c:/tmp/imagem.png“. Se você conseguir fazer funcionar o template com uma imagem vinda de uma URL, me avise depois nos comentários.

E com isso finalizamos o exemplo onde exibimos uma toast notification (que é uma funcionalidade disponível apenas nas APIs do WinRT) através de uma aplicação desktop. Veja outros exemplos de utilização de APIs do WinRT em aplicações desktop:

E você? Já utilizou ou está pensando em utilizar uma das APIs do WinRT no seu aplicativo desktop? Deixe um comentário logo abaixo contando pra gente quais foram as suas experiências.

Espero que você tenha gostado e que o conteúdo desse artigo seja útil no seu dia-a-dia. E caso você queira ficar por dentro de todas as novidades do meu site, além de receber dicas que eu só compartilho por e-mail, assine a minha newsletter.

Até a próxima!

André Lima

Image by Ceo1017 used under Creative Commons
https://www.flickr.com/photos/65839047@N07/6176933305/

4 thoughts on “Utilizando APIs do WinRT em aplicações desktop

Deixe uma resposta

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