Introduction
Windows Phone provides developers the programmatic ability to access contacts that enables them to build experiences that integrate tightly with the native contacts experience.
The Windows Phone platform supports integration with contacts in two ways:
1. It supports read-only access to the phone’s contacts store. This support is available in all versions of Windows Phone operating systems.
2. It supports creation of a custom contact store associated with an application. This is only supported in Windows Phone 8 and allows adding, reading, updating and deleting contacts in the custom contact store. There is also API support to sync the custom contacts to a remote storage location in the cloud for backup purposes.
Contacts Basics
Windows Phone supports access to contacts from the following data sources:
- Windows Phone device
- Windows Live Social
- Exchange accounts
- Mobile operate address book
- Contacts in the custom contacts store
Access to contacts is enabled by using the Contacts class in the Microsoft.Phone.UserData namespace.
The Contacts class has the SearchCompleted event, which is fired when a search for contacts completes.
To have access to contacts, the Windows Phone application will need to declare the capability ID_CAP_CONTACTS in the application manifest file WMAppManifest.xml.
The Contacts.SearchAsync API is used to search for a specific contact by providing a filter. The ContactsSearchEventArgs object is returned as part of the SearchCompleted delegate.
Hands On
We will build a simple application that searches for contacts with a specified first name or email address.
For this hands on, we will use Visual Studio 2013 and build a Windows Phone 8 application.
Create a new Visual Studio Windows Phone project titled WPContactDemo.
New Project
Under the Solution Explorer, expand Properties and double-click WMAppManifest.xml.
Double-click WMAppManifest.xml
Click on Capabilities and select ID_CAP_CONTACTS to declare the application’s capability to access contacts.
Select ID_CAP_CONTACTS
Next, we will add a few TextBox controls and a Button control to MainPage.xaml as shown below.
Add TextBox controls and a Button control
In our application, we will search for contacts by one of the following: First name, Last Name or Email address. We will also add a ListBox control below the search button to display our results.
Our XAML for the mainpage is below (added sections are highlighted).
<phone:PhoneApplicationPage x:Class="WPContactDemo.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" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" shell:SystemTray.IsVisible="True"> <!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!-- LOCALIZATION NOTE: To localize the displayed strings copy their values to appropriately named keys in the app's neutral language resource file (AppResources.resx) then replace the hard-coded text value between the attributes' quotation marks with the binding clause whose path points to that string name. For example: Text="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}" This binding points to the template's string resource named "ApplicationTitle". Adding supported languages in the Project Properties tab will create a new resx file per language that can carry the translated values of your UI strings. The binding in these examples will cause the value of the attributes to be drawn from the .resx file that matches the CurrentUICulture of the app at run time. --> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/> <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBox x:Name="textBoxFirstName" HorizontalAlignment="Left" Height="72" Margin="178,25,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="268"/> <TextBlock HorizontalAlignment="Left" Margin="60,50,0,0" TextWrapping="Wrap" Text="First Name" VerticalAlignment="Top"/> <TextBox x:Name="textBoxEmailAddress" HorizontalAlignment="Left" Height="72" Margin="178,147,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="268"/> <TextBlock HorizontalAlignment="Left" Margin="34,172,0,0" TextWrapping="Wrap" Text="Email address" VerticalAlignment="Top"/> <Button x:Name="buttonSearchContacts" Content="Search" HorizontalAlignment="Left" Margin="216,258,0,0" VerticalAlignment="Top" Click="buttonSearchContacts_Click"/> <ListBox x:Name="listContacts" ItemsSource="{Binding}" HorizontalAlignment="Left" Height="224" Margin="60,340,0,0" VerticalAlignment="Top" Width="348"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" > <TextBlock Name="ContactResults" Text="{Binding Path=DisplayName, Mode=OneWay}" FontSize="{StaticResource PhoneFontSizeExtraLarge}" Margin="18,8,0,0" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> <!--Uncomment to see an alignment grid to help ensure your controls are aligned on common boundaries. The image has a top margin of -32px to account for the System Tray. Set this to 0 (or remove the margin altogether) if the System Tray is hidden. Before shipping remove this XAML and the image itself.--> <!--<Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" Height="800" Width="480" Margin="0,-32,0,0" Grid.Row="0" Grid.RowSpan="2" IsHitTestVisible="False" />--> </Grid> </phone:PhoneApplicationPage>
If you observe closely, you will notice that for the listbox, we have a template associated with displaying the “Display name” of the contact in the results.
To search on an input, we will wire up the Search button’s click event with code that will parse the search criteria and invoke the Contacts.SearchAsync API.
In the click event, we will create an instance of the Contacts store, and register an event handler for the search completion event. We will also invoke the search APIs depending on whether the search is by Display name or email address.
private void buttonSearchContacts_Click(object sender, RoutedEventArgs e) { Contacts contactStore = new Contacts(); contactStore.SearchCompleted += contactStore_SearchCompleted; if (textBoxFirstName.Text != "") contactStore.SearchAsync(textBoxFirstName.Text, FilterKind.DisplayName, "Searching by first name"); if (textBoxEmailAddress.Text != "") contactStore.SearchAsync(textBoxEmailAddress.Text, FilterKind.EmailAddress, "Searching by email address"); }
Finally, we will implement the event handler for the Search completion event.
Here, we will set the data context of the ListBox control to the Results property of ContactsSearchEventArgs object.
void contactStore_SearchCompleted(object sender, ContactsSearchEventArgs e) { MessageBox.Show(e.State.ToString()); listContacts.DataContext = e.Results; }
Our application is now ready. You can now run the application to test search your contacts by Display name or email address. The sample code for the demo is available below.
Summary
In this article, we learned a few basics about accessing Contacts on a Windows Phone. I hope you have found this article useful.
About the Author
Vipul Patel is a Program Manager currently working at Amazon Corporation. He has formerly worked at Microsoft in the Lync team and in the .NET team (in the Base Class libraries and the Debugging and Profiling team). He can be reached at vipul.patel@hotmail.com