Integrando o botão voltar do Windows Phone com o controle WebBrowser

Recentemente trabalhei em um projeto para Windows Phone onde a aplicação continha um mix de telas xaml e webviews (páginas web hospedadas nos servidores da empresa). O uso de webviews era um requisito da empresa pois as funcionalidades existentes nessas páginas não estavam disponíveis por meio de apis e tais apis não serão disponibilizadas no futuro próximo.

Para dar uma boa experiência para os usuários da aplicação, queríamos que o botão voltar do aparelho também afetasse a navegação do webview, fazendo com que o usuário não perceba que estã em uma webview e a aplicação inteira tenha um comportamento consistente. Já vi várias aplicações no Windows Phone que usam webviews sem fazer isso e a experiência é péssima pois você está no webview, usa o voltar do aparelho para tentar ir para a página anterior e acaba saindo da navegação do webview por completo e indo para a tela anterior ao webview (o aplicativo Audible é um exemplo desse comportamento ruim).

Para fazer essa integração com o botão voltar não basta assinar o evento do voltar do telefone e chamar o voltar do webbrowser pois é necessário saber se o webbrowser ainda tem para onde voltar e temos que tomar cuidado para não entrar em um looping de backstack (navegando entre páginas que foram chamadas usando o back, fazendo com que a pilha nunca acabe).

Para realizar isso de forma correta, precisamos controlar a navegação do webview. Esse controle consiste em criar e manter uma lista contendo as urls navegadas e um método que decide se o webview ainda pode voltar. A única limitação da solução proposta neste post é que ela só funciona corretamente para casos onde a navegação entre as páginas em modo webview passa parametros via url (querystring) e não via post. Se alguma página for navegada via post, o back pode não vai voltar para ela como o usuário espera. No caso da aplicação que eu estava trabalhando isso não seria um problema, mas se fosse seria necessária uma solução bem mais complexa que envolveria injeção de javascript nas páginas do webview.

O controle da navegação é feito assinando o evento “Navigated” do controle WebBrowser. Abaixo segue o código comentado usado nesse event handler.

int GoingBack = 0; //contador indicando se está voltando
Uri CurrentPage = null;
Stack<Uri> NavigationStack = new Stack<Uri>(); //pilha de navegação

///


/// conta quantas páginas foram navegadas para saber se pode voltar.
/// ignora a contagem quando a navegação foi feita usando back
///

void webview_Navigated(object sender, NavigationEventArgs e) {
    lock (this) {
        if (GoingBack > 0) {
            GoingBack--;
        } else {
            if (CurrentPage != null) {
                NavigationStack.Push(CurrentPage);//acrescenta a página de onde está saindo na pilha de navegação
            }
        }
        CurrentPage = e.Uri;
    }
}

O NavigationEventArgs do evento acima tem uma propriedade chamada NavigationMode que teoricamente indicaria se a navegação é do tipo New, Back, Forward ou Refresh, mas não está sendo usada pois ela não indicou os valores corretos nos meus testes, mesmo quando eu estava usando “history.back();” ou “history.go(-1);” via javascript injection no webview. Por isso foi necessário controlar se está sendo feita navegação de back e quais páginas estão na pilha.

O segundo método usado para esse processo é o responsável por tentar efetuar a navegação do webview para a página anterior e informar se conseguiu.

///


/// Tenta navegar o browser para a página anterior. Se conseguir retorna true, se não houver página anterior ou der erro, retorna false.
///

bool TryGoBack() {
    lock (this) {
        if (NavigationStack.Count > 0) {
            try {
                GoingBack++;
//incrementa o contador de navegação voltando
                webview.Navigate(NavigationStack.Pop()); //remove a última página navegada da pilha e navega para ela
                return true;
            } catch { }
        }
    }
    return false;
}

A última parte do processo todo é assinar o evento do botão back do telefone usando o código abaixo:

protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e) {
    e.Cancel = TryGoBack();
    if (!e.Cancel) base.OnBackKeyPress(e);
}

Se sua aplicação tiver mais de um lugar que utilize webviews, você pode criar um controle para encapsular o webbrowser e os 2 primeiros métodos, mas o evento do botão voltar deverá ser assinado em cada página que usar esse controle, pois não é possível assinar o evento do voltar a partir de controle. Não esqueça de fazer o método TryGoBack ser public se encapsular o controle, para poder chamar a partir da página.

DISCLAIMER: Este código é disponibilizado “as is”, e atende às necessidades descritas acima, mas deve ser bem testado para garantir que funcionará da forma desejada em outras aplicações. Este código funciona tanto para Windows Phone 7 como 8.

Xbox One no Brasil

Unboxing Xbox One / Kinect

No dia 22 de novembro de 2013 ocorreu o lançamento do Xbox One em 13 países, entre eles o Brasil (quem diria?). Comprei o meu em pré-venda online dia 22/06 e recebi no dia 25/11.

Fiquei muito contente pelo simples fato de o Brasil ter feito parte do primeiro grupo de países onde o novo console seria disponibilizado, algo que não é muito comum para nenhum tipo de lançamento de artigos de tecnologia, mas talvez isso seja um sinal de que estão começando a dar maior importância para o Brasil de uma forma geral.

[continuar lendo]

Windows 8 + Xbox 360 + compartilhamento via charm de dispositivos

Acabei de publicar um vídeo no Youtube mostrando um exemplo de aplicação para Windows 8 usando charm de devices para exibir vídeo no Xbox. No futuro vou fazer um artigo mostrando como programar seu aplicativo para Windows 8 para que suporte essa funcionalidade mas por enquanto, assistam ao vídeo e tirem proveito do recurso que já está presente em alguns aplicativos da Loja do Windows 8, como por exemplo as apps de Música, Fotos, Vídeos.

Este vídeo foi feito utilizando o Surface RT e Nokia Lumia 920 com WP8 que todos os que foram ao Build 2012 ganharam.

MVP em Silverlight pelo terceiro ano seguido!

Acabei de receber o comunicado de que o meu MVP em Silverlight foi renovado pelo terceiro ano consecutivo! Quem aí quer prova maior de que o Silverlight ainda está no páreo?

Este ano será excepcional para todos nós, desenvolvedores XAML. Prevejo muito Silverlight, Windows Phone e Windows 8 no futuro.

Que comece outro ano de XAML!