André Alves de Lima

Talking about Software Development and more…

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:

Manage NuGet Packages

 Adicionando a referência ao MVVM Light Toolkit

Uma vez adicionado o MVVM Light Toolkit, vamos adicionar também outro pacote que iremos precisar, que se chama WinRTConverters:

Adicionando a referência ao 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:

Modo de voo no Windows 8

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

Deixe uma resposta

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