25 09 2013
Detectando conexão à Internet em aplicativos para a Windows Store
Olá caro leitor!
Se você está desenvolvendo aplicativos para a Windows Store (aplicativos Metro), provavelmente você utiliza em algum momento a conexão com a Internet para realizar alguma operação. Obviamente, antes de fazer esse processo, normalmente você gostaria de saber se o usuário está atualmente com uma conexão disponível. No artigo de hoje veremos como você pode fazer essa verificação.
Vamos começar o exemplo criando uma aplicação para a Windows Store. Na MainPage que é criada automaticamente, vamos criar uma interface bem simples, contendo somente um StackPanel com dois TextBlocks, um com o texto “Conectado” e outro com o texto “Desconectado”. A ideia é que quando a conexão com a Internet estiver disponível, o TextBlock “Conectado” seja exibido e, obviamente, quando a conexão não estiver disponível, o TextBlock “Desconectado” seja exibido:
<Page x:Class="ExemploWinRT_DetectandoConexaoInternet.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:ExemploWinRT_DetectandoConexaoInternet" 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}"> <StackPanel Orientation="Vertical" Margin="50"> <TextBlock Text="Conectado!" Style="{StaticResource HeaderTextStyle}" Foreground="#DE7AE81F"/> <TextBlock Text="Desconectado!" Style="{StaticResource HeaderTextStyle}" Foreground="#DEFD1616"/> </StackPanel> </Grid> </Page>
O próximo (e mais importante) passo é criar uma classe que terá o papel de detectar se a conexão com a Internet está disponível no momento. Para deixar essa classe mais interessante, podemos também adicionar um evento que será disparado quando o estado da conexão com a Internet for alterado. Veja abaixo como ficaria essa classe, que no exemplo chamei de InternetConectionHelper:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Windows.Networking.Connectivity; namespace ExemploWinRT_DetectandoConexaoInternet { /// <summary> /// Classe que auxilia na detecção do estado da conexão com a Internet. /// </summary> public static class InternetConnectionHelper { #region Atributos e Propriedades /// <summary> /// Indica se uma conexão à Internet está disponível no momento. /// </summary> public static bool ConexaoDisponivel { get { var internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile(); return internetConnectionProfile != null; } } #endregion #region Eventos /// <summary> /// Simples forwarding do evento NetworkStatusChanged da classe NetworkInformation. /// </summary> public static event NetworkStatusChangedEventHandler ConexaoDisponivelChanged { add { NetworkInformation.NetworkStatusChanged += value; } remove { NetworkInformation.NetworkStatusChanged -= value; } } #endregion } }
Como você pode reparar no código acima, para detectarmos se a conexão com a Internet está disponível no WinRT, utilizamos a classe NetworkInformation, presente no namespace
Windows.Networking.Connectivity. O método estático GetInternetConnectionProfile da classe NetworkInformation retorna as informações do perfil de conexão com a Internet e, como já era de se esperar, caso esse método retorne nulo, isso significa que uma conexão com a Internet não está disponível no momento.
Parece lógico, certo? Porém, isso não é tudo! É aqui que 90% dos artigos relacionados a esse assunto acabam falhando! Caso você esteja utilizando algum tipo de hypervisor (Hyper-V, VirtualBox, etc), provavelmente você tem um adaptador virtual para conexões com a Internet que são utilizados por suas máquinas virtuais. Nesse cenário, o método GetInternetConnectionProfile não retorna nulo, mesmo que você esteja sem conexão com a Internet (até mesmo em Flight Mode do Windows 8)! E aí então, como resolver essa zica? Fácil! É só fazer uma pequena alteração na nossa propriedade ConexaoDisponivel, de forma que, caso o método GetInternetConnectionProfile não retorne nulo, nós verificamos se o ConectivityLevel do objeto retornado é InternetAccess. Veja só:
/// <summary> /// Indica se uma conexão à Internet está disponível no momento. /// </summary> public static bool ConexaoDisponivel { get { var internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile(); // Não basta checar se InternetConnectionProfile é nulo (como muitos exemplos encontrados na Internet), porque ele nunca será nulo caso você // tenha algum adaptador virtual (por exemplo HyperV ou VirtualBox adapters). Portanto, precisamos checar também se o connectivity level do // InternetConnectionProfile é "InternetAccess". return internetConnectionProfile != null && internetConnectionProfile.GetNetworkConnectivityLevel().Equals(Windows.Networking.Connectivity.NetworkConnectivityLevel.InternetAccess); } }
Pronto. Agora sim a classe está preparada para detectar corretamente se a conexão com a Internet está disponível ou não, mesmo se você estiver utilizando Hyper-V ou algo do tipo. Vamos então agora conectar os TextBlocks da nossa MainPage com a propriedade ConexaoDisponivel da nossa classe, porém, quero fazer isso utilizando MVVM, que eu sempre procuro utilizar nos meus exemplos. O toolkit que costumo utilizar é o MVVM Light Toolkit. Para adicioná-lo ao projeto, basta utilizarmos o NuGet Package Manager:
Uma vez adicionado o MVVM Light Toolkit, vamos adicionar também outro pacote que iremos precisar, que se chama WinRTConverters:
Com esses pacotes em mãos, vamos ao nosso App.xaml, onde temos que corrigir uma pequena falha que ocorre com o MVVM Light Toolkit quando utilizado em aplicações para a Windows Store. Basicamente faça uma busca no arquivo App.xaml por “clr-namespace:” (sem aspas) e substitua por “using:“. Agora compile o projeto para garantir que tudo está funcionando até esse ponto.
Aproveitando que estamos no arquivo App.xaml, vamos adicionar uma instância da classe BooleanToVisibilityConverter, que é um dos converters disponíveis na biblioteca WinRTConverters e que precisaremos no nosso exemplo. O código final do arquivo App.xaml deve ficar parecido com este:
<?xml version="1.0" encoding="utf-8"?> <Application x:Class="ExemploWinRT_DetectandoConexaoInternet.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:ExemploWinRT_DetectandoConexaoInternet" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="using:ExemploWinRT_DetectandoConexaoInternet.ViewModel" xmlns:visibilityconverters="using:WinRTConverters.Visibility" mc:Ignorable="d"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!-- Styles that define common aspects of the platform look and feel Required by Visual Studio project and item templates --> <ResourceDictionary Source="Common/StandardStyles.xaml" /> </ResourceDictionary.MergedDictionaries> <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" /> <visibilityconverters:BooleanToVisibilityConverter x:Name="BooleanToVisibilityConverter" /> </ResourceDictionary> </Application.Resources> </Application>
Agora é hora de ajustarmos a ViewModel que utilizaremos na nossa MainPage. Ao adicionarmos a referência ao MVVM Light Toolkit, a classe MainViewModel é criada automaticamente dentro da pasta ViewModel no nosso projeto. É essa ViewModel que utilizaremos na nossa MainPage. Na MainViewModel, vamos criar uma propriedade chamada ConexaoDisponivel, que simplesmente é um atalho para a propriedade de mesmo nome que se encontra na nossa classe InternetConectionHelper criada anteriormente. Além disso, precisamos fazer um hook no evento ConexaoDisponivelChanged que chamará o método RaisePropertyChanged da nossa MainViewModel. Como essa propriedade está bindada na interface, precisamos utilizar o Dispatcher para chamar o método RaisePropertyChanged. Com isso em mente, o código da MainViewModel ficaria assim:
/// <summary> /// ViewModel contendo as propriedades e comandos a serem bindados na Main View. /// </summary> public class MainViewModel : ViewModelBase { #region Atributos e Propriedades /// <summary> /// Atalho para a propriedade de mesmo nome da classe InternetConnectionHelper. Adicionada na ViewModel para implementar suporte a change notification. /// </summary> public bool ConexaoDisponivel { get { return InternetConnectionHelper.ConexaoDisponivel; } } #endregion #region Construtores /// <summary> /// Constroi uma instância de MainViewModel, realizando outras tarefas necessárias. /// </summary> public MainViewModel() { // Quando o evento ConexaoDisponivelChanged é disparado na classe InternetConnectionHelper, precisamos notificar a alteração da propriedade ConexaoDisponivel // para que a UI seja atualizada caso necessário. InternetConnectionHelper.ConexaoDisponivelChanged += (s) => GalaSoft.MvvmLight.Threading.DispatcherHelper.CheckBeginInvokeOnUI(() => RaisePropertyChanged("ConexaoDisponivel")); } #endregion }
O próximo passo é adicionar os bindings nos nossos TextBlocks da MainPage de forma que eles utilizem a propriedade ConexaoDisponivel da nossa ViewModel. No primeiro TextBlock (que tem o texto “Conectado!”) faremos um binding normal com essa propriedade, utilizando o converter BooleanToVisibilityConverter criado anteriormente. Já no segundo TextBlock (que tem o texto “Desconectado!”), faremos também um binding com a mesma propriedade e também utilizaremos o mesmo converter, porém, passando como parâmetro para o converter o valor booleano “True”. Dessa forma, o converter agirá de forma invertida, ou seja, quando a propriedade ConexaoDisponivel estiver true, o TextBlock estará invisível, e quando ela estiver false, o TextBlock estará visível. Além disso, precisamos configurar o DataContext da nossa página apontando para a nossa MainViewModel. Faremos isso utilizando o ViewModelLocator do MVVM Light Toolkit. Veja como fica o XAML final da nossa MainPage:
<Page x:Class="ExemploWinRT_DetectandoConexaoInternet.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:ExemploWinRT_DetectandoConexaoInternet" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" DataContext="{Binding Main, Source={StaticResource Locator}}"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <StackPanel Orientation="Vertical" Margin="50"> <TextBlock Text="Conectado!" Style="{StaticResource HeaderTextStyle}" Foreground="#DE7AE81F" Visibility="{Binding ConexaoDisponivel, Converter={StaticResource BooleanToVisibilityConverter}}" /> <TextBlock Text="Desconectado!" Style="{StaticResource HeaderTextStyle}" Foreground="#DEFD1616"> <TextBlock.Visibility> <Binding Path="ConexaoDisponivel" Converter="{StaticResource BooleanToVisibilityConverter}"> <Binding.ConverterParameter> <x:Boolean>True</x:Boolean> </Binding.ConverterParameter> </Binding> </TextBlock.Visibility> </TextBlock> </StackPanel> </Grid> </Page>
Por fim, como nós utilizamos o DispatcherHelper do MVVM Light Toolkit na nossa MainViewModel, precisamos inicializá-lo a partir do construtor da nossa MainPage. Para isso, vá até o code behind da MainPage e adicione a seguinte linha no construtor, logo após a chamada de InitializeComponent:
GalaSoft.MvvmLight.Threading.DispatcherHelper.Initialize();
Pronto! Com isso temos um exemplo completo que mostra como gerenciar e responder à alteração da conexão à Internet a partir de aplicativos para a Windows Store. Para testar o exemplo, execute o projeto e tente ativar o modo de voo no seu computador para habilitar e desabilitar a conexão à Internet:
E com isso concluímos mais um artigo da série sobre desenvolvimento de aplicativos para a Windows Store. Você encontra o código completo desse exemplo no meu GitHub, bem como nos meus exemplos da MSDN Galery.
Espero que tenham gostado! Até a próxima semana!
André Lima
Explorando as in-app purchases em aplicativos para a Windows Store Criando um simples formulário de parâmetros em Windows Forms