Renderização assíncrona de HTML

Como primeiro guia de código vou tentar demostrar uma funcionalidade simples de exibir uma pagina HTML em uma Metro App. Neste exemplo será citado:

  • XAML Data binding;
  • INotifyPropertyChanged;
  • Async e Await no C# 4.5;
  • Regex;
  • WebView Control;

Brincando de desenhar a tela

Mesmo com pouco conhecimento em XAML é bem fácil a assimilação para quem já tem conhecimento de desenvolvimento para web (html ou silverlight), inicialmente a tela é dividia em uma Grid, no nosso exemplo somente com duas linhas. Na primeira linha separei o titulo do blog apenas para ilustrar e na segunda linha ficara os controles de entrada de texto para receber a URL, um botão para receber o evento de atualizar a pagina e o próprio controle de WebView para exibir a pagina. Desing XAMLCódigo do arquivo XAML:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="73*"/>
            <RowDefinition Height="311*"/>
        </Grid.RowDefinitions>  
        <TextBlock x:Name="lblTitulo" Grid.Row="0" HorizontalAlignment="Left" Margin="50,50,0,0" VerticalAlignment="Top" Text="Mapa do Metro Blog" FontSize="48"/>
        <TextBlock x:Name="lblTitulo2" Grid.Row="0" HorizontalAlignment="Left" Margin="80,100,0,0" VerticalAlignment="Top" Text="https://mapadometro.wordpress.com/    … Desenvolvimento para Windows Metro User Interface" FontSize="18"/>
        <TextBox x:Name="txtUrl" Grid.Row="1" Margin="10,10,73,0" Text="{Binding Resultado, Mode=TwoWay}" VerticalAlignment="Top" FontSize="20" FontWeight="Bold"/>
        <Button x:Name="btnOK" Grid.Row="1" Content="Go!" HorizontalAlignment="Right" Margin="0,10,10,580" VerticalAlignment="Center" Click="btnOK_Click" Background="White" BorderBrush="#FF2A9EFF" Foreground="Black" Height="32" FontSize="12"/>
        <WebView x:Name="navegadorWebView" Margin="10,54,10,10" Grid.Row="1"/>
    </Grid>

Data Binding

Não seria necessário, porem apenas para introduzir o conceito de Data Binding, que é um meio de ligação da interface (xaml) com os controles no codigo (C#). Essa ligação geralmente é definida pela expressão Binding, no exemplo do controle txtUrl a propriedade Text recebeu um Binding da propriedade Resultado de algum objeto datasource, ate esse momento ainda não especificado. Ainda nesse controle txtUrl foi definido o modo de binding TwoWay, isto é, a atualização dessa propriedade na tela atualiza a propriedade do objeto da mesma forma que qualquer modificação do propriedade no codigo será refletida na tela.

<TextBox x:Name="txtUrl" Grid.Row="1" Margin="10,10,73,0" Text="{Binding Resultado, Mode=TwoWay}" VerticalAlignment="Top" FontSize="20" FontWeight="Bold"/>

Para ligar os objetos no arquivo .xaml.cs criei uma classe Exemplo para falar um pouco sobre a implementação da interface INotifyPropertyChanged, necessária para implementar o binding. Segue abaixo a classe:

    public class Exemplo : INotifyPropertyChanged
    {
        private string _resultado;

        // Declaracao do evento do PropertyChanged.
        public event PropertyChangedEventHandler PropertyChanged;

        // Propriedade que sera a fonte do binding.
        public string Resultado
        {
            get { return _resultado; }
            set
            {
                _resultado = value;

                // Chamada do NotifyPropertyChanged quando o valor é alterado.
                NotifyPropertyChanged("Resultado");
            }
        }

        // Metodo que ira notificar a mudana
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

No método de inicialização será adicionado as linhas abaixo para setar os valores iniciais e o binding do datasource:

        Exemplo exemplo;

        public MainPage()
        {
            this.InitializeComponent();

            exemplo = new Exemplo();
            exemplo.Resultado = "http://";

            txtUrl.DataContext = exemplo;
        }

Requisição da Pagina via HTTP

A ideia é exibir uma pagina Web no controle WeView e existe varias maneiras de conseguir esse resultado, o caminho mais logico seria setar o endereço URI da pagina no controle através da propriedade Source. Por algum motivo neste exemplo vamos primeiro adquirir o conteúdo do html através de um request assíncrono bem simples, a vantagem é que desta forma da a possibilidade de analisar ou incrementar o conteúdo html antes de exibi-lo.

No evento click do botão btnOK será realizado antes de qualquer coisa uma verificação via Expressão regular, que provê uma forma concisa e flexível de identificar cadeias de caracteres de interesse, como caracteres particulares, palavras ou padrões de caracteres. No exemplo usei uma verificação Regex de url bem simples (^http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$) caso a entrada informada não seja uma url valida, a cor do texto ficará cinza afim de dar um feedback ao usuário, caso a url seja valida o texto receberá a cor verde.

        private async void btnOK_Click(object sender, RoutedEventArgs e)
        {
            // Realiza a validação da URL em Regex
            Match match = Regex.Match(exemplo.Resultado, @"^http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$", RegexOptions.IgnoreCase);

            // Se foi informado uma url valida
            if (match.Success)
            {
                // Chamada assíncrona
                string result = await RenderizacaoHTML(new Uri(exemplo.Resultado));

                // Seta o conteudo no controle WebView
                navegadorWebView.NavigateToString(result);

                txtUrl.Foreground = new SolidColorBrush(Colors.Green);
            }
            else
            {
                // Apenas muda a cor do texto para Cinza
                txtUrl.Foreground = new SolidColorBrush(Colors.Gray);
            }
        }

Async e Await

No trecho de código anterior note que na declaração do método inicia com “private async …” a keyword async fornece uma indicação ao framework que na execução deste método será potencialmente de longa duração sem bloquear thread da origem que foi invocado. A chamada do método RenderizacaoHTML exige a keyword await, por que este metodo tambem foi declarado como async. O await é um operador aplicado a chamadas assincronas de metodos que suspende a execução do metodo atual ate que o método invocado sejá completada. O método RenderizacaoHTML é bem simples apenas utiliza as classes do System.Net.Http.HttpClient para realizar uma requisição do conteúdo html da url informada.

        // Consulta um endereco http e responde o conteudo em texto
        public async Task<string> RenderizacaoHTML(Uri endereco)
        {
            HttpClient http = new System.Net.Http.HttpClient();
            HttpResponseMessage response = await http.GetAsync(endereco);
            return await response.Content.ReadAsStringAsync();
        }

Final

 

 

Se essa informação foi útil para você, compartilhe no twitter e deixe um comentário.

Gostaria muito do seu feedback para melhor o blog.

Anúncios

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s