信息
您所需的主题如下所示。但此主题未包含在此库中。

如何执行 Windows Phone 8 基本的自定义联系人存储操作

2014/6/18

仅适用于:Windows Phone 8 和 Windows Phone Silverlight 8.1

本主题演示如何为应用创建自定义联系人存储,以及如何执行基本的操作(例如,添加、更新和删除联系人)。

本主题包括以下部分。

说明注意:

自定义联系人存储 API 仅提供对由您的应用创建的联系人的访问。如果您的应用需要只读访问手机的联系人存储或日历,应使用不同的 API。有关更多信息,请参见对 Windows Phone 8 联系人和日历的只读访问

每个 Windows Phone 应用可以拥有一个联系人存储。您可以通过调用 CreateOrOpenAsync 打开存储。如果存储尚不存在,在您调用此方法时将创建存储。此方法的重载版本接收一个 ContactStoreSystemAccessMode 枚举成员和一个 ContactStoreApplicationAccessMode 枚举成员,它们指定系统和其他应用对您的联系人存储有多少访问权。ContactStoreSystemAccessMode.ReadOnly 指示只有您的应用才可以修改您的联系人。ContactStoreSystemAccessMode.ReadWrite 指手机可以通过其内置的联系人体验修改您的联系人。ContactStoreApplicationAccessMode.LimitedReadOnly 指其他应用仅可读取联系人的显示名称和资料图片。ContactStoreApplicationAccessMode.ReadOnly 指其他应用可以读取联系人的所有属性。默认设置为 ContactStoreSystemAccessMode.ReadOnlyContactStoreApplicationAccessMode.LimitedReadOnly

在打开联系人存储之后,您可以通过调用 StoredContact 构造函数创建新的联系人,该构造函数将传入对您的存储的引用。StoredContact 对象具有内置的属性用于若干常用联系人数据,例如名字和姓氏。每个联系人还具有包含本地 ID 的字段(由操作系统自动分配)和存储远程 ID(可由您的应用设置)的字段。您可以使用远程和本地 ID 将手机上应用联系人存储中的联系人与云中的远程联系人存储关联。

警告说明警告:

如果您的应用使用 ContactStore API,而且使用 StoredContact.RemoteId 属性将存储在手机上的联系人与远程存储的联系人链接起来,那么 RemoteId 属性的值既要稳定,又要唯一,这一点很关键。这意味着,远程 ID 应一致地识别单个用户帐户而且应包含唯一标记,以保证它不会与手机上其他联系人(包括其他应用所拥有的联系人)的远程 ID 冲突。如果您尝试保存不具有唯一 RemoteId 属性值的 StoredContact,则该保存操作可能失败。

如果无法保证您的应用所使用的远程 ID 稳定且唯一,那么您可以使用本主题后面所演示的 RemoteIdHelper 类,以便在将您的所有远程 ID 添加至系统之前,为它们添加唯一标记。或者,您可以选择不使用 RemoteId 属性,而是创建自定义的扩展属性,将您的联系人远程 ID 存储在里面。

除了由 StoredContact 对象提供的字段,您还可以通过调用 GetExtendedPropertiesAsync 添加更多属性。这将返回可用联系人数据填充的键值对的字典。如果要让字段与手机内部联系人属性名称一致,可以将 KnownContactProperties 类的字段用于键值。或者可以指定任何任意字符串作为键。在设置了联系人属性之后,可通过调用 SaveAsync 将其保存到存储。

下列代码演示添加联系人的简单实现。


async public void AddContact(string remoteId, string givenName, string familyName, string email, string codeName)
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();

    StoredContact contact = new StoredContact(store);
    contact.RemoteId = remoteId;
    contact.GivenName = givenName;
    contact.FamilyName = familyName;

    IDictionary<string, object> props = await contact.GetExtendedPropertiesAsync();
    props.Add(KnownContactProperties.Email, email);
    props.Add("Codename", codeName);

    await contact.SaveAsync();

}


您可以通过从存储检索联系人、修改其属性然后再次保存来更新联系人。下列代码示例使用 FindContactByRemoteIdAsync 检索联系人(使用其远程 ID)。您还可以调用 FindContactByLocalIdAsync 检索联系人(通过本地 ID)。然后,将修改联系人的属性并调用 SaveAsync 将联系人保存到存储。


async private void UpdateContact(string remoteId, string givenName, string familyName, string email, string codeName)
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();
    StoredContact contact = await store.FindContactByRemoteIdAsync(remoteId);

    if (contact != null)
    {
        contact.GivenName = givenName;
        contact.FamilyName = familyName;

        IDictionary<string, object> props = await contact.GetExtendedPropertiesAsync();
        props[KnownContactProperties.Email] = email;
        props["Codename"] = codeName;

        await contact.SaveAsync();
    }
}


通过调用 DeleteContactAsync 和传入待删除联系人的本地 ID 来删除联系人。如果要删除基于远程 ID 的联系人,可调用 FindContactByRemoteIdAsync 然后使用 Id 属性的值调用 DeleteContactAsync


async private void DeleteContact(string localID)
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();
    await store.DeleteContactAsync(localID);   
}


您可以通过调用 CreateContactQuery 查询存储中的所有联系人。此方法的无参数版本返回每个联系人的默认字段集合,并使用默认排序。在返回的 ContactQueryResult 对象上调用 GetContactsAsync 来检索返回的联系人列表。


async private void DefaultQuery()
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();
    ContactQueryResult result = store.CreateContactQuery();
    IReadOnlyList<StoredContact> contacts = await result.GetContactsAsync();

    Dispatcher.BeginInvoke(() => { ContactListBox.DataContext = contacts; });
}


如果存在您知道您将需要访问的 KnownContactProperties 的子集,您可以创建一个新的 ContactQueryOptions,然后将属性名称添加到 DesiredFields 矢量,以指定在进行查询时应获取它们。您仍应调用 GetPropertiesAsync 来访问字段值,但是因为它消除了对数据库的额外查询,从而指定所需字段可以优化性能。

您还可以设置 OrderBy 以更改用于排序结果的字段,但是建议您使用默认排序,因为这会在整个应用上提供一致的用户体验。


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

    ContactQueryOptions options = new ContactQueryOptions();
    options.DesiredFields.Add(KnownContactProperties.Email);
    options.DesiredFields.Add("Codename");

    ContactQueryResult result = store.CreateContactQuery(options);
    IReadOnlyList<StoredContact> contacts = await result.GetContactsAsync();

    Dispatcher.BeginInvoke(() => { ContactListBox.DataContext = contacts; });
}


如上所述,为了使用自定义联系人的 RemoteId 字段,您应确保该 ID 值在手机上的所有应用中都是唯一的。如果您基于云的联系人存储不使用保证为唯一的 ID,您可以将以下类添加至您的项目,这将帮助您在将联系人保存至存储之前,向您的 ID 添加唯一标记。它也将帮助您在从存储中检索到该 ID 后,从 ID 中移除此唯一标记,以便您可以取回您原始的远程 ID。下面的示例演示 RemoteIdHelper 类的定义。


class RemoteIdHelper
{
    private const string ContactStoreLocalInstanceIdKey = "LocalInstanceId";

    public async Task SetRemoteIdGuid(ContactStore store)
    {
        IDictionary<string, object> properties;
        properties = await store.LoadExtendedPropertiesAsync().AsTask<IDictionary<string, object>>();
        if (!properties.ContainsKey(ContactStoreLocalInstanceIdKey))
        {
            // the given store does not have a local instance id so set one against store extended properties
            Guid guid = Guid.NewGuid();
            properties.Add(ContactStoreLocalInstanceIdKey, guid.ToString());
            System.Collections.ObjectModel.ReadOnlyDictionary<string, object> readonlyProperties = new System.Collections.ObjectModel.ReadOnlyDictionary<string, object>(properties);
            await store.SaveExtendedPropertiesAsync(readonlyProperties).AsTask();
        }
    }

    public async Task<string> GetTaggedRemoteId(ContactStore store, string remoteId)
    {
        string taggedRemoteId = string.Empty;

        System.Collections.Generic.IDictionary<string, object> properties;
        properties = await store.LoadExtendedPropertiesAsync().AsTask<System.Collections.Generic.IDictionary<string, object>>();
        if (properties.ContainsKey(ContactStoreLocalInstanceIdKey))
        {
            taggedRemoteId = string.Format("{0}_{1}", properties[ContactStoreLocalInstanceIdKey], remoteId);
        }
        else
        {
            // handle error condition
        }

        return taggedRemoteId;
    }

    public async Task<string> GetUntaggedRemoteId(ContactStore store, string taggedRemoteId)
    {
        string remoteId = string.Empty;

        System.Collections.Generic.IDictionary<string, object> properties;
        properties = await store.LoadExtendedPropertiesAsync().AsTask<System.Collections.Generic.IDictionary<string, object>>();
        if (properties.ContainsKey(ContactStoreLocalInstanceIdKey))
        {
            string localInstanceId = properties[ContactStoreLocalInstanceIdKey] as string;
            if (taggedRemoteId.Length > localInstanceId.Length + 1)
            {
                remoteId = taggedRemoteId.Substring(localInstanceId.Length + 1);
            }
        }
        else
        {
            // handle error condition
        }

        return remoteId;
    }

}


在向存储中保存任何联系人之前,请创建新的 RemoteIdHelper,并调用 SetRemoteIdGuid。该操作为您的应用创建 GUID,并把它存储在您的联系人存储的扩展属性中。您可以多次调用该方法。如果已经存在 GUID,它将不会被重写。

无论何时,如果您需要使用远程 ID 执行操作,请首先将其传递至 GetTaggedRemoteId,以检索附有您的应用的 GUID 的 ID 副本。

如果您需要从保存在联系人存储中的远程 ID 中获取您的原始远程 ID,则调用 GetUntaggedRemoteId,它会移除唯一标记,返回原始 ID。

vCard 是用于电子名片的标准文件格式。ContactInformation 类公开 ParseVcardAsnc 方法,该方法在指定的 URI 处异步分析 vCard,然后返回一个填充的 ContactInformation 对象。在将此对象和对联系人存储的引用传递到 StoredContact 构造函数后,将调用 SaveAsync 保存联系人。

下列示例代码演示了如何从 vCard 将联系人保存到您的自定义联系人存储。

task<StoredContact^> SaveFromVcard(ContactStore^ store, String^ uriToVcard)
{
    // Invoke the parser on the passed-in URI.
    return create_task(ContactInformation::ParseVcardAsync(ref new Uri(uriToVcard)))
    .then([=] (ContactInformation^ info) -> StoredContact^
    {
        // When that's done, wrap a stored contact around it, save.
        auto contact = ref new StoredContact(store, info);
        create_task(contact->SaveAsync()).get();

        return contact;
    });
}

显示: