Storing Contacts in the Custom Contact Store

,

Beginning with Windows Phone 8, each Windows Phone app is provided with its own contact store. Your app can add or remove contacts from the store, and contacts that are present in the store are displayed in the phone’s People Hub.

The contact store is retrieved by calling the Windows.Phone.PersonalInformation.ContactStore class’s static CreateOrOpenAsync method. If the store does not exist, it is created the first time the method is called. To add a contact to the contact store, create a StoredContact instance and call its SaveAsync method, as demonstrated in the following example:

ContactStore store = await ContactStore.CreateOrOpenAsync();
StoredContact contact = new StoredContact(store)
    {RemoteId = remoteId, GivenName = "Annie", FamilyName = "Easley"};

await contact.SaveAsync();

ContactStore.CreateOrOpenAsync has an overload that allows you to control the visibility of contacts within the store to other apps. The signature of the method is as follows:

CreateOrOpenAsync(ContactStoreSystemAccessMode access,
     ContactStoreApplicationAccessMode sharing)

The ContactStoreSystemAccessMode and ContactStoreApplicationAccessMode enumeration parameters specify the level of access the system and other apps have to your app’s contact store. ContactStoreSystemAccessMode can be either ReadOnly or ReadWrite. ReadOnly indicates that only your app can modify your contacts. ReadWrite means that the phone can modify your contacts through its built-in contacts experience that can be reached via the People Hub.

ContactStoreApplicationAccessMode can be either LimitedReadOnly or ReadOnly. LimitedReadOnly means that other apps can read only the display name and the profile picture of your app’s contacts, whereas ReadOnly allows other apps to read all the properties of your contacts.

The default settings are ContactStoreSystemAccessMode.ReadOnly and ContactStoreApplicationAccessMode.LimitedReadOnly.

StoredContact contains the following properties for storing a contact’s personal details:

Image DisplayName

Image DisplayPicture

Image FamilyName

Image GivenName

Image HonorificPrefix

Image HonorificSuffix

Image Id

Image RemoteId

If not explicitly set in your code, the DisplayName property getter returns a concatenation of the following properties:

HonorificPrefix + GivenName + FamilyName + HonorificSuffix

The Id property is a read-only string that is assigned by the contact store when the contact is saved. Id can be used to retrieve a particular contact from the store, as shown in the following example:

ContactStore store = await ContactStore.CreateOrOpenAsync();
StoredContact contact = await store.FindContactByIdAsync(id);

The RemoteId property is also used to retrieve a contact. But, unlike the Id property, it is not read-only and can be set to a value that is known by your back-end system; such as a field in a database table. The following example demonstrates how to retrieve a contact using its remote ID:

ContactStore store = await ContactStore.CreateOrOpenAsync();
StoredContact contact = await store.FindContactByRemoteIdAsync(id);

The DisplayPicture property returns a Windows.Storage.Streams.IRandomAccessStreamReference to an image that is set either by the user via the People Hub or by your app using the StoredContact class’s SetDisplayPictureAsync method, which is discussed later in the chapter.

If the data you want to associate with your contact does not fit into any of the StoredContact properties, the class also offers a property dictionary for storing any number of other pieces of information. The following excerpt demonstrates how to save an email address along with the StoredContact object:

IDictionary<string, object> properties = await contact.GetExtendedPropertiesAsync();
properties.Add(KnownContactProperties.Email, email);

The built-in KnownContactProperties class provides various strongly typed names of common contact properties. You can use the fields of the KnownContactProperties class for key values if you want the fields to be consistent with the phone’s internal contact property names.

Property names, however, are not limited to those in the KnownContactProperties class. Indeed, you can supply any key value that you want, as demonstrated in the following excerpt:

properties.Add("Partner Name", "Mary");

To delete a contact from the store, either call DeleteAsync on an existing StoredContact object or use the DeleteContactAsync method, as shown in the following example:

ContactStore store = await ContactStore.CreateOrOpenAsync();
await store.DeleteContactAsync(id);

Now that you have looked at the essential operations of the contact store, the next section explores the sample for this section. The source code is located in the ContactsAndAppointments/CustomContactStore directory in the WPUnleashed.Example project of the downloadable sample code.

The sample contains two views: ContactStoreView and ContactCreationView, and two associated viewmodels: ContactStoreViewModel and ContactCreationViewModel.

ContactStoreViewModel loads the list of StoredContacts from the app’s contact store. Each contact can be either deleted via a DeleteContactCommand or viewed in detail via a ViewContactCommand.

The Load method of the ContactStoreViewModel retrieves the list of contacts from the contact store (see Listing 14.9). The ContactQueryOptions class allows you to specify the known properties that you want returned using its DesiredFields property. In the current version of the Windows Phone SDK, however, the DesiredFields property appears to serve no purpose.

Use the OrderBy property of the ContactQueryOptions to specify the order of the results returned by the query. OrderBy is an enumeration value and can be either SystemDefault, FamilyNameGivenName, or GivenNameFamilyName.


Note

To provide a consistent user experience across different apps, use the default ordering (ContactQueryResultOrdering.SystemDefault) to order contact query results.


The ContactStoreViewModel class’s Contacts property is set to the list returned by the store.

LISTING 14.9. ContactStoreViewModel.Load Method


public async void Load()
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();

    /* These values are not used in the view, but merely demonstrates
     * how to load them as part of the query. */
    ContactQueryOptions options = new ContactQueryOptions();
    options.OrderBy = ContactQueryResultOrdering.SystemDefault;

    ContactQueryResult contactQuery = store.CreateContactQuery(options);
    IReadOnlyList<StoredContact> storedContacts
        = await contactQuery.GetContactsAsync();

    Contacts = storedContacts;
}


The ContactStoreViewModel class’s DeleteContactCommand calls the DeleteContact method, which deletes the contact and reloads the contact list, as shown:

async void DeleteContact(StoredContact storedContact)
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();
    await store.DeleteContactAsync(storedContact.Id);

    Load();
}

The ContactStoreViewModel class’s ViewContactCommand calls the ViewContact method, which uses the viewmodel’s base class method to navigate to the ContactCreationView page; passing it the ID of the StoredContact via a query string parameter, as shown:

void ViewContact(StoredContact storedContact)
{
    Navigate("/ContactsAndAppointments/CustomContactStore/"
        + "ContactCreationView.xaml?ContactId=" + storedContact.Id);
}

The ContactStoreView page uses a ListBox to display the list of contacts retrieved by the viewmodel (see Listing 14.10). An image displays a delete icon. The image element uses the custom commanding infrastructure to bind to the DeleteContactCommand in the viewmodel.

Tapping on the TextBlock containing the DisplayName of the StoredContact, executes the ViewContactCommand.

The use of the bridge resource allows the data template to reach outside of its data context to bind to properties of the ContactStoreViewModel instance.

An AppBarHyperlinkButton allows the user to create a new contact by navigating to the ContactCreationView without passing a contact ID.

LISTING 14.10. ContactStoreView.xaml (excerpt)


<u:AppBar>
    <u:AppBarHyperlinkButton
        NavigateUri="/ContactsAndAppointments/.../ContactCreationView.xaml"
                Text="new contact"
                IconUri="/ContactsAndAppointments/.../Images/Add.png" />
</u:AppBar>
...
<ListBox ItemsSource="{Binding Contacts}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid d:DataContext="{d:DesignInstance p:StoredContact}"
                    Margin="0,0,0,20">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <Image Source="/ContactsAndAppointments/.../Delete.png"
                        c:Commanding.Command="{Binding Content.DeleteContactCommand,
                                          Source={StaticResource bridge}}"
                        c:Commanding.CommandParameter="{Binding}" />

                <TextBlock Text="{Binding DisplayName}"
                            Style="{StaticResource PhoneTextLargeStyle}"
                            c:Commanding.Command="{Binding Content.ViewContactCommand,
                                           Source={StaticResource bridge}}"
                            c:Commanding.CommandParameter="{Binding}"
                            Grid.Column="1" />
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>


Figure 14.36 shows the ContactStoreView page with a number of contacts present in the app’s contact store.

Image

FIGURE 14.36 ContactStoreView page.

When the user taps a name in the list of contacts, the app navigates to the ContactCreationView page, which passes the query string dictionary containing the contact ID to the ContactCreationViewModel class, as shown:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    ViewModel.Load(NavigationContext.QueryString);
}

If a contact ID is not present in the query string, the viewmodel creates a new contact, or else assumes its edit mode for an existing contact (see Listing 14.11) and retrieves and copies the properties of the contact to matching viewmodel properties.

LISTING 14.11. ContactCreationViewModel.Load Method


public async void Load(IDictionary<string, string> queryString)
{
    string id;

    if (!queryString.TryGetValue("ContactId", out id))
    {
        return;
    }

    ContactStore store = await ContactStore.CreateOrOpenAsync();
    StoredContact contact = await store.FindContactByIdAsync(id);

    if (contact != null)
    {
        contactId = id;

        GivenName = contact.GivenName;
        FamilyName = contact.FamilyName;
        HonorificPrefix = contact.HonorificPrefix;

        IDictionary<string, object> extendedProperties
            = await contact.GetExtendedPropertiesAsync();

        object tempEmail;
        extendedProperties.TryGetValue(KnownContactProperties.Email, out tempEmail);
        EmailAddress = (string)tempEmail;

        object tempCodeName;
        extendedProperties.TryGetValue("CodeName", out tempCodeName);
        CodeName = (string)tempCodeName;
    }
}


The ContactCreationViewModel class contains a SaveContactCommand that calls the SaveContact method, shown in Listing 14.12. The various viewmodel properties are copied to a new or existing contact. The method retrieves an image resource, which becomes the contact’s display picture. The contact is then saved and the page navigates back to the ContactStoreView page.

LISTING 14.12. ContactCreationViewModel.Save Method


async void SaveContact()
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();

    StoredContact contact;

    if (string.IsNullOrEmpty(contactId))
    {
        contact = new StoredContact(store);
    }
    else
    {
        contact = await store.FindContactByIdAsync(contactId);
    }

    contact.GivenName = givenName;
    contact.FamilyName = familyName;
    contact.HonorificPrefix = honorificPrefix;

    IDictionary<string, object> extendedProperties
        = await contact.GetExtendedPropertiesAsync();
    extendedProperties[KnownContactProperties.Email] = emailAddress;
    extendedProperties["CodeName"] = codeName;

    Uri uri = new Uri("ContactsAndAppointments/CustomContactStore/Images/Contact.png",
                                UriKind.Relative);
    StreamResourceInfo resourceInfo = Application.GetResourceStream(uri);
    using (var stream = resourceInfo.Stream)
    {
        await contact.SetDisplayPictureAsync(stream.AsInputStream());
    }

    await contact.SaveAsync();

    Navigate("/ContactsAndAppointments/CustomContactStore/ContactStoreView.xaml");
}


Figure 14.37 shows the ContactCreationView page. Tapping the save button adds or updates the contact in the app’s contact store.

Image

FIGURE 14.37 ContactCreationView page.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.236.108