Mobile Zone is brought to you in partnership with:

I love technology. Plain and simple. You can generally find me writing software, figuring out how to get rid of cable, playing on my Xbox, or traveling around this country speaking about software development. If you're doing something cool with technology, let me know. I'd love to hear your story about something amazing. You can find my blog at jeffblankenburg.com Jeff is a DZone MVB and is not an employee of DZone and has posted 71 posts at DZone. You can read more from them at their website. View Full User Profile

31 Days of Mango | Day #8: Contacts API

11.08.2011
| 2783 views |
  • submit to reddit

This article is Day #8 in a series called 31 Days of Mango.

Day8-ContactsAPI

If you would like to try the application I cover in the article on your device, you can download it from the Windows Phone Marketplace.

DownloadIcon


Today we are going to talk about a new namespace available on Windows Phones: Microsoft.Phone.UserData.  In the original 31 Days of Windows Phone, I covered a topic on Day #8 called Choosers.  With these Tasks, we were able to prompt a user to select a record from their list of contacts on their phone, and retrieve a specific piece of data from that contact: an email address or a phone number, but not both at once.

With this new namespace in Windows Phone 7.5, we now have the ability to treat the user’s contact list like a local database.  We can search it, grab multiple contacts, and get their entire contact record.  It’s much more robust, but working with it is also much more manual.

As a note, just as Peter Parker’s uncle Ben reminded him, “with great power comes great responsibility.”  Just because you have access to a user’s contact list does not mean you should exploit this privilege.  Getting your app installed on a user’s phone requires a high level of trust. If you violate that trust by spamming all of their friends and contacts with email and other junk, not only will you be uninstalled, but your user’s frustration will also be reflected in negative reviews in the marketplace.

Finally, it’s important to remember that the data we are accessing is READ-ONLY.  We can’t make updates, delete anything, or even add anything.  This is simply a mechanism to find some or all of the contacts on a user’s phone, and use that data within our apps.

Building Our User Interface

As with all of our articles in this series, we first need to start with a user interface.  In this example, we are using the standard Windows Phone Application template, and I’ve added a ListBox with some binding statements that we’ll use later.  For more on data binding in XAML, you can check out Day #13 of the 31 Days of Silverlight.  I’ve also added a TextBox that we will use for searching through the contacts.

Here’s the XAML that we’ll be using for this application:

<phone:PhoneApplicationPage
   x:Class="Day8_ContactsAPI.MainPage"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
   FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait" Orientation="Portrait"
   shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="31 DAYS OF MANGO - DAY #8" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="contacts api" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBox x:Name="SearchTerm" Height="80" Margin="0,-12,0,539" TextChanged="SearchTerm_TextChanged" />
            <ListBox x:Name="ContactList" Margin="0,70,0,0">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=DisplayName, Mode=OneWay}" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Grid>
</phone:PhoneApplicationPage> 

The specific things to notice in this XAML is our ListBox, named “ContactList,” and the TextBlock inside it’s DataTemplate.  We have bound this TextBlock to the value DisplayName, which is what we’re going to be retrieving from our user’s contact list.  The other important piece is the TextBox named “SearchTerm.”  We will use the contents of that box as our search criteria by implementing the TextChanged event handler.  Here’s what our final interface will look like when we’re done:

image

Searching for Contact Data

In our code-behind file, we need to make sure we have a using statement for the Microsoft.Phone.UserData namespace.  This is what allows us to access the contact info on the device.

The first step is to capture any text changes from our TextBox.  We’re already defined the event handler in our XAML, but we need to create the event handler method.  Here is our initial C# code, with the event handler created:

using System;
using System.Linq;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using Microsoft.Phone.UserData;

namespace Day8_ContactsAPI
{
    public partial class MainPage : PhoneApplicationPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void SearchTerm_TextChanged(object sender, TextChangedEventArgs e)
        {
            SearchContacts(SearchTerm.Text);
        }

        private void SearchContacts(string searchterm)
        {
             //PERFORM THE SEARCH
        }
    }
}
 

As you can see, the SearchTerm_TextChanged fires every time the value in our TextBox changes, and I’ve set it up so that we call a separate method, SearchContacts, to actually perform the search.  SearchContacts takes a string parameter, and we’ll use this value in our actual search code.

In order to actually search the data, however, we need to create a new intance of the Contacts object.  (This is what we need the Microsoft.Phone.UserData namespace for.)  In order to get this data, we need to perform an asynchronous search against the Contacts data.  The Contacts object has an event handler, SearchCompleted, that we will use to grab the results of our search when it is completed.  Finally, we’ll use the SearchAsync() method to execute the search with specific criteria.  Let’s take a look at our final C#, and then I’ll spend some time talking about the different search parameters we can use.

using System;
using System.Linq;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using Microsoft.Phone.UserData;

namespace Day8_ContactsAPI
{
    public partial class MainPage : PhoneApplicationPage
    {
        Contacts contacts = new Contacts();

        public MainPage()
        {
            InitializeComponent();
            contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted);
            SearchContacts(String.Empty);
        }

        private void SearchTerm_TextChanged(object sender, TextChangedEventArgs e)
        {
            SearchContacts(SearchTerm.Text);
        }

        void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
        {
            ContactList.ItemsSource = e.Results;
        }

        private void SearchContacts(string searchterm)
        {
            contacts.SearchAsync(searchterm, FilterKind.DisplayName, null);
        }
    }
} 

As you can see in our constructor method, we call the SearchContacts method we created earlier, passing in String.Empty.  By using an empty string, we indicate to the SearchAsync() method that we want ALL of the contacts.  While this will work fine in the emulator (it only has 7 contacts by default), a user’s phone can have thousands of records, and could take a few seconds to load.  Keep this in mind as you use this functionality, and consider using a ProgressBar or some other mechanism to let the user know you’re still gathering data.

If you look at the signature for the Contacts.SearchAsync method, it takes three parameters:

  • string – this is the search criteria you’re using.  In our example, it’s the contents of the TextBox that we created in our XAML file.
  • FilterKind – this allows you to search only by PhoneNumber, DisplayName, or EmailAddress.  If you select None, your search criteria string will be ignored.
  • object – this is an object parameter that you can use to pass data into the search so that when you receive the results, you know something about what you were trying to accomplish.  This can be as simple as a string identifier, all the way up to a specific object that you’ll need later.


If you run your application right now, you should see that whatever you type in the TextBox will filter the results in your ListBox.  Here’s a look at a filtered list in the Windows Phone emulator:

image

Looking At The Raw Data

So, we’ve successfully queried the Contacts on the device, and bound it to a ListBox.  What we haven’t seen, however, is what kinds of data we can actually get, and it’s abundant.  Also, because we receive an IEnumerable collection of data from our search, we can use LINQ to query against our results.

I’m modified the contacts_SearchCompleted method from our example above, grabbing the first record from the data, and just storing some of the values in local variables for demonstration.  You would be more likely to show this data on the screen, or save it to your app’s storage mechanism.  Here’s what that new method looks like, with some of the properties of a Contact object exposed for you:

void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
{
    ContactList.ItemsSource = e.Results;

    //Grabbing the first record of our result.
    Contact patientZero = e.Results.FirstOrDefault();

    string firstname = patientZero.CompleteName.FirstName;
    string lastname = patientZero.CompleteName.LastName;

    string emailaddress = patientZero.EmailAddresses.FirstOrDefault().EmailAddress;
    string phonenumber = patientZero.PhoneNumbers.FirstOrDefault().PhoneNumber;

    bool isPinnedToStart = patientZero.IsPinnedToStart;
} 

The example above is just a small sampling of the data available to you in a Contact record, and depending on your needs, just about everything is there.  Here’s a quick list of what you can get (assuming it’s available in the Contact record).

  • Accounts – the list of accounts that this contact is associated with.  This includes things like Facebook, Windows Live, Outlook, etc.
  • Addresses – the list of addresses for this contact.  Each address also includes the “account” (from above) that it is associated with, the “kind” of address it is (like work, home, etc.), and finally PhysicalAddress, which exposes all of the expected values like Address1, City, StateProvince, and CountryRegion.
  • Birthdays – I’m not sure why a user would have different birthdays, but each “account” might have a different value, so you get a list.  Also, if a year isn’t specified, you’ll get a value of “1” for the year in those cases.
  • Children – a simple list of strings that represent the names of the children of the contact.
  • Companies – again enriched with the accounts data, this includes values like JobTitle, CompanyName, and OfficeLocation.
  • CompleteName – shown in our code sample above, this contains all the properties of a contact’s name, including Title, Suffix, MiddleName, etc.
  • DisplayName – a simple string that represents the name that is used on the phone for this contact.
  • EmailAddresses – a list of email addresses, with “account” and “kind” data as well.
  • IsPinnedToStart – this is an interesting piece of boolean data, because it generally indicates which of this user’s contacts are the most important to them (because the contact is pinned to the user’s start screen.)
  • Notes – a list of strings that the user has saved as notes about this contact.
  • PhoneNumbers – a list of all of the phone number associated with a contact, this is also decorated with “accounts” and “kind” data.’
  • SignificantOthers – you’d like to think there’s only one value for this as well, but…you know…  Anyways, this is similar to the Children property.  A list of strings.
  • Websites – a list of the websites associated with this contact, stored as strings.

Finally, I want to make sure you have a visual for what this application will look like, so here’s a quick video showing off the application we just built:

So, I think that’s a pretty good starter kit for using the Contacts API on a Windows Phone.  This entire namespace is only available on phones running the Windows Phone 7.5 OS, so if you’re working on a 7.0 application, you won’t be able to use it. (But really, why are you still building a 7.0 app?  It’s time to upgrade!)

To download a working Windows Phone solution that uses all of the code from this article, click on the Download Code button below:

download

Tomorrow, we are going to talk about the other side of the UserData namespace, the Calendar API.  It’s another read-only set of data, but it allows us to have some visibility into a user’s availability in a certain time period.  See you then!

toolsbutton

 

Published at DZone with permission of Jeff Blankenburg, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

John Pedersen replied on Thu, 2011/11/10 - 4:33am

Is it possible to take the Contact-object from the UserData namespace and open that contact in the people-hub?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.