André Alves de Lima

Talking about Software Development and more…

Acessando a lista de contatos em aplicativos para a Windows Store

A lista de contatos do usuário é um dos ativos mais importantes que podemos utilizar dentro dos nossos aplicativos. No artigo de hoje aprenderemos como acessar os contatos do Windows através de um aplicativo para a Windows Store.

Desde a chegada do Windows 8, a Microsoft adicionou um catálogo de contatos diretamente no sistema operacional. Essa lista de contatos está disponível no Windows 8 através da tilePeople“:

Os contatos exibidos nessa tela são uma junção dos contatos de todas as contas adicionadas ao Windows 8, como Hotmail (ou Outlook.com), Gmail, Facebook, Twitter, etc. O mais interessante é que é possível selecionar esses contatos de dentro de nosso aplicativo. Vejamos como podemos fazer isso abaixo.

Selecionando um item do catálogo de contatos

Para demonstrar essa funcionalidade, vamos criar uma “Windows Store Blank App“. No projeto criado, vamos abrir o XAML da MainPage e adicionar alguns controles para exibir os dados do contato que vamos selecionar:

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel VerticalAlignment="Top"
                    HorizontalAlignment="Left"
                    Margin="50">
            <TextBox x:Name="Nome"
                     Header="Nome" 
                     Width="400"
                     IsEnabled="False" />
            <TextBox x:Name="Sobrenome"
                     Header="Sobrenome"
                     Width="400"
                     IsEnabled="False" />
            <TextBox x:Name="Email"
                     Header="Email"
                     Width="400"
                     IsEnabled="False" />
            <TextBox x:Name="Telefone"
                     Header="Telefone"
                     Width="400"
                     IsEnabled="False" />
            <Button Content="Selecionar Contato"
                    Click="SelecionarContatoButton_Click" 
                    HorizontalAlignment="Stretch"/>
        </StackPanel>

E então vamos até o code-behind da MainPage e adicionemos o código que será executado ao clicarmos no botão para selecionar um contato:

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void SelecionarContatoButton_Click(object sender, RoutedEventArgs e)
        {
            // Invocando o ContactPicker, tela onde o usuário pode selecionar um contato do seu catálogo.
            ContactPicker picker = new ContactPicker();
            var contact = await picker.PickContactAsync();

            // Se o usuário cancelar a operação, o retorno será null.
            if (contact != null)
            {
                Nome.Text = contact.FirstName;
                Sobrenome.Text = contact.LastName;
                if (contact.Emails.Any())
                    Email.Text = contact.Emails.First().Address;
                if (contact.Phones.Any())
                    Telefone.Text = contact.Phones.First().Number;
            }
        }
    }

Agora vamos analisar o código acima. A classe ContactPicker é responsável por exibir um diálogo para que o usuário selecione um ou mais contatos. Ao criarmos uma instância de ContactPicker, podemos basicamente chamar dois métodos: PickContactAsync (para fazermos a seleção de um contato) ou PickContactsAsync (para fazermos a seleção de um ou mais contatos). No exemplo acima, utilizei o método PickContactAsync, porque eu quero selecionar somente um contato, e não múltiplos contatos.

O retorno do método PickContactAsync é uma instância da classe Contact. Observe que temos que verificar se o retorno não foi nulo, porque o usuário pode muito bem cancelar a operação do ContactPicker, e nesse caso, o retorno será null. Uma vez tendo a instância da classe Contact em mãos, podemos utilizar qualquer uma das inúmeras propriedades disponíveis. No nosso caso, só estamos utilizando as propriedades FirstName, LastName, Emails e Phones. Confira a lista de propriedades da classe Contact:

Note que algumas propriedades da classe Contact foram marcadas como “deprecated“, e não devem ser utilizadas. Fique de olho na descrição da propriedade que você escolher utilizar:

Um outro ponto importante de se observar é que o método PickContactAsync, como o próprio nome já indica, é assíncrono. Devido a esse detalhe, precisamos utilizar a keywordawait” quando realizamos a sua chamada. Além disso, o nosso event handler obrigatoriamente deve conter a keywordasync” na sua declaração.

Execute a aplicação, clique em “Selecionar Contato” e veja que a sua lista de contatos é exibida. Ao selecionar um contato e clicar em “OK“, os dados do contato são transferidos para os TextBoxes da nossa aplicação.

Na próxima seção desse artigo nós veremos como pesquisar e exibir o “cartão” de um contato.

Pesquisando um contato e exibindo o seu cartão

Além do ContactPicker, a API de contatos dos aplicativos para a Windows Store disponibiliza uma forma de pesquisarmos um contato e exibirmos o seu cartão. O cartão do contato é aquela UI que o Windows mostra quando selecionamos um contato no nosso catálogo. Por exemplo, esse é o cartão do contato da minha esposa:

A pesquisa de contatos pode ser feita através do ID interno do contato, e-mail ou telefone. Infelizmente a busca mais útil, que seria por nome, não foi implementada até o momento.

Para realizar uma pesquisa e exibir o cartão de um contato, precisamos utilizar a classe ContactManager. Essa classe possui o método ShowContactCard, que é justamente o método que vamos utilizar para mostrar o cartão do contato que foi selecionado no nosso exemplo.

Abra novamente o XAML da MainPage da nossa aplicação de exemplo e adicione o botão para exibirmos o cartão do contato:

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel VerticalAlignment="Top"
                    HorizontalAlignment="Left"
                    Margin="50">
            <TextBox x:Name="Nome"
                     Header="Nome" 
                     Width="400"
                     IsEnabled="False" />
            <TextBox x:Name="Sobrenome"
                     Header="Sobrenome"
                     Width="400"
                     IsEnabled="False" />
            <TextBox x:Name="Email"
                     Header="Email"
                     Width="400"
                     IsEnabled="False" />
            <TextBox x:Name="Telefone"
                     Header="Telefone"
                     Width="400"
                     IsEnabled="False" />
            <Button Content="Selecionar Contato"
                    Click="SelecionarContatoButton_Click" 
                    HorizontalAlignment="Stretch"/>
            <Button x:Name="MostrarCartaoButton"
                    Content="Mostrar Cartão"
                    Click="MostrarCartaoButton_Click"
                    HorizontalAlignment="Stretch" 
                    IsEnabled="False"/>
        </StackPanel>
    </Grid>

Como você pode perceber, a ideia é que o botão de mostrar o cartão venha inicialmente desabilitado. Ele será habilitado assim que o usuário selecionar um contato através da opção “Selecionar Contato“. Agora vamos para o code-behind implementar as alterações necessárias para que esse novo botão funcione como esperado.

A primeira alteração que precisamos fazer é criarmos um atributo na MainPage para guardarmos o ID do contato selecionado. Além disso, assim que o usuário selecionar um contato, precisamos habilitar o botão “Mostrar Cartão“:

        private string _contactID = string.Empty;

        private async void SelecionarContatoButton_Click(object sender, RoutedEventArgs e)
        {
            // Invocando o ContactPicker, tela onde o usuário pode selecionar um contato do seu catálogo.
            ContactPicker picker = new ContactPicker();
            var contact = await picker.PickContactAsync();

            // Se o usuário cancelar a operação, o retorno será null.
            if (contact != null)
            {
                Nome.Text = contact.FirstName;
                Sobrenome.Text = contact.LastName;
                if (contact.Emails.Any())
                    Email.Text = contact.Emails.First().Address;
                if (contact.Phones.Any())
                    Telefone.Text = contact.Phones.First().Number;
                _contactID = contact.Id;
                MostrarCartaoButton.IsEnabled = true;
            }
        }

Finalmente, vamos adicionar o handler para o clique do botão “Mostrar Cartão“:

        private void MostrarCartaoButton_Click(object sender, RoutedEventArgs e)
        {
            // Criando o contato com o ID selecionado anteriormente.
            Contact c = new Contact();
            c.Id = _contactID;

            // Criando um Rect que representa o local onde o cartão deve ser exibido (no nosso caso, embaixo do botão).
            var button = sender as Button;
            GeneralTransform transform = button.TransformToVisual(this);
            Rect transformedRect = transform.TransformBounds(new Rect(0, 0, button.ActualWidth, button.ActualHeight));

            // Exibing o cartão do contato.
            ContactManager.ShowContactCard(c, transformedRect);
        }

Note que o método ShowContactCard recebe dois parâmetros: o contato a ser exibido e um “Rect” que representa o local onde o cartão deve ser apresentado. O parâmetro com o contato é muito simples: basta criarmos uma instância da classe Contact e configurar o ID do contato que foi selecionado anteriormente. Já para o segundo parâmetro, criamos o Rect chamando o método TransformToVisual do botão (passando a Window) e depois chamando o método TransformBounds passando as coordenadas dos cantos da Window.

Execute a aplicação, selecione um contato e depois clique em “Mostrar Cartão“. Veja que o cartão é exibido logo abaixo do botão:

Como mencionei anteriormente, além de utilizar o ID para mostrar o cartão do contato, é possível realizar uma busca por e-mail ou telefone. Para isso, basta configurar uma dessas propriedades na instância de Contact que será passada para o método ShowContactCard. Um pequeno detalhe é que, para que a engine de contatos realmente encontre o contato, o e-mail ou telefone precisam bater exatamente com o que está cadastrado no contato, senão ele não será encontrado. Isso é um pouco frustrante, porque limita bastante o poder de buscar um contato, mas, de qualquer forma já é um bom começo.

Caso você passe mais de uma dessas propriedades para o Contato, existe um grau de precedência para a busca. Primeiramente a engine considera o ID do Contato, e depois o e-mail e telefone têm pesos iguais na busca. Veja o trecho da documentação da API abaixo, onde é tratado esse tópico da ordem da busca:

Contact must contain at least an Id, Emails, or a phone number from a Phones list to query the user’s contact database to retrieve a matching contact to display. Id has higher priority for querying. If an Id matches, the rest of query parameters will be ignored for matching purposes. If an Id does not find a match, the query uses the rest of query parameters. Emails and Phones have equal priority for matching. If multiple email addresses, or phone numbers, or both are provided, the query first performs an exact match, requiring all query parameters to match a system contact record. If this results in no matches, the query uses “best effort” match, in which a match of any query parameters is sufficient. If no matches occur, the data in the input contact displays in the contact card. If a match occurs, only system contact data displays, and the data in the input contact is discarded.

Conclusão

A API de contatos das aplicações para a Windows Store é eficiente para darmos ao usuário a opção de selecionar um contato do sistema operacional e, consequentemente, utilizarmos os dados desse contato. Porém, se você está procurando uma API que proporcione busca de contatos, você provavelmente vai acabar ficando na mão. A busca só funciona por ID, e-mail ou telefone, e esses dados devem bater exatamente com o que está cadastrado no contato.

De qualquer forma, vale a pena dar uma olhada na sua aplicação e analisar se não cabe integrar a seleção de contatos. Então, não perca tempo, teste esse exemplo e integre essa funcionalidade no seu aplicativo, e depois me conte nos comentários o que você achou!

Aproveito para pedir novamente que você se inscreva para receber a minha newsletter, onde eu comento sobre os posts da semana, além de dar dicas e truques os quais eu não publico em nenhum outro lugar!

Até a próxima!

André Lima

Image by Phil Whitehouse used under Creative Commons
https://www.flickr.com/photos/philliecasablanca/2078244730/

Deixe uma resposta

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