原文:Windows Phone 8 - 建立App专属联络人资讯(ContactStore)

在WP7的时候介绍了如何操作联络人的功能,例如:<Windows Phone 7 - 存取联络人与行事历资料>。

到了WP8之後增加了一个非常不一样的联络人相关的API:ContactStore,也是该篇文章要介绍的主题。

?

什麽是ContactStore

?提供让App可以建立自己专属的Contact Store(联络人储存区);

?系统会自动将建立好的Contact Store整合入People Hub中。

?除了在App操作既有的Contact集合的资讯(例如:Windows Live、Facebook…等),

?? 也可以增加自订的Custom Properties加以扩充;

??? => 需注意自订的Custom Properties需储存於Contact Store中;

??? => 并不会显示在People Hub的Contact Card上,而是需要透过App加以程序化操作;

?ContactStore API提供让App自订义的Contact store可与现有Contact Store加以同步与比对变化;

?

[注意]

?每一个App只能有一个Contact Store;

?App建立Contact Store後,系统在整合入People Hub时,可能会造成People Hub在使用上会有lag的状况;

?? => 不用担心,等系统整合完毕後该问题即不存在。

?App建立的contact Store自动整合入People Hub,如果不想让People Hub看起来很混乱;

?? => 可至「设定->应用程式->联络人->筛选我的联络人清单」,取消勾选该App的资源来源。

?

可以利用下图来说明ContactStore与系统、其他应用程式的关系:

一个App可以建立一个专属的ContactStore,并且设定该ContactStore被系统或其他Apps存取的权限,

在操作透过StoredContact物件为单位;App经由Cloud Data Source取得最新的资讯并同步至既有的StoredContact里,

而同步的方式则是依赖StoredContact.RemoteId的属性来维持一致性,所以每一个RemoteId必需是unique的。

?

?

往下便加以针对ContactStore的相关命名空间与类别加以说明:

?

Windows.Phone.PersonalInformation namespace

??? 主要提供APIs负责管理自订的contact store。透过下表来概要说明具有的元素:

类型 名称 说明
Class ContactAddress Represents a civic address for StoredContact objects.
? ContactChangeRecord Represents a change in contact information that occurred between revisions.
? ContactInformation Represents a contact without an association to a contact store.
? ContactQueryOptions Represents query options for retrieving contacts using CreateContactQuery.
? ContactQueryResult Represents the result of a contact query.

在建立ContactQueryResult可搭配ContactQueryOptions指定查询的条件与排序的方式。

重要的方法:
?GetContactCountAsync??? Gets the number of contacts in the contact store.

?GetContactsAsync()
??? Retrieves contacts from the contact store.

?GetContactsAsync(UInt32, UInt32)??? Retrieves contacts from the contact store given the specified starting index and
??? number of items to return.
?
?GetCurrentQueryOptions??? Gets the current query options.
? ContactStore Represents the custom contact store for a Windows Phone app.
? KnownContactProperties Provides key names for accessing known properties for StoredContact or ContactInformation objects.
? StoredContact Represents a contact associated with a custom contact store.
Enumerations ContactChangeType Indicates the type of change represented by a ContactChangeRecord.
? ContactQueryResultOrdering The order in which contacts are returned from CreateContactQuery.
? ContactStoreApplicationAccessMode Specifies the application access mode for a custom contact store created with CreateOrOpenAsync.
? ContactStoreSystemAccessMode Specifies the system access mode for a custom contact store created with CreateOrOpenAsync.
? VCardFormat The format of a vCard.
Interface IContactInformation Defines the interface for contact information.

在使该用该Namepsace下的元素时要,要记得开启对应的<Capabilities />:「ID_CAP_CONTACTS 」。

?

上述大致上列出该Namesapce具有的元素,往下一一针对如何操作ContactStore与使用StoredContact来加以说明。

?

ContactStroe

??? 为代表每一个App专属的custom contact store。搭配CreateOrOpenAsync()建立或开启contact store,搭配StoredContact物件加以

操作该contact store里的资料。往下说明可用的方法与使用方式:

类型 名称 说明
Property RevisionNumber Read-only。取得contact store的版本号。
Method CreateContactQuery() 使用预设的查询选项建立一个contact query已取得ContactQueryResult。
? CreateContactQuery(ContactQueryOptions) 使用自订的查询选项建立一个contact query已取得ContactQueryResult。
?ContactQueryOptions
??? 用於指定contact query的查询选项,具有二个属性可以使用:
??? > DesiredField:ready-only,设定/取得查询结果的contact要显示的属性清单;
??? > OrderBy:设定/取得查询结果的contact要用那一个栏位进行排序;
? CreateOrOpenAsync() 开启App专属的custom contact store,如果该store不存在预设会自动建立一个。
? CreateOrOpenAsync(ContactStoreSystemAccessMode, ContactStoreApplicationAccessMode) 开启App专属的custom contact store,如果该store不存在预设会自动建立一个。
搭配ContactStoreSystemAccessMode与ContactStoreApplicationAccessMode来指定contact store被存取的权限,说明如下:

?ContactStoreSystemAccessMode

?? 指定系统本身操作该contact store的方式:

?? > ReadOnly:系统仅能读取该contact store;

?? > ReadWrite:系统可以修改该contact store中的contacts;

????????????????????? (through its built-in contacts experience.)

?ContactStoreApplicationAccessMode

?? 指定其他应用程式可以操作该contact store的方式:

?? > LimitedReadOnly:只能读取store中contacts的description、display picture;

?? > ReadOnly:可以读取所有store中contacts的属性;

?

预设指定为:ContactStoreSystemAccessMode.ReadOnly与ContactStoreApplicationAccessMode.LimitedReadOnly;

? DeleteAsync 删除custom contact store。
? DeleteContactAsync 删除custom contact store中指定contact ID的Contact。
? FindContactByIdAsync 检索custom contact store中指定contact ID的Contacts,取得IAsyncOperation<StoredContact>的集合。
? FindContactByRemoteIdAsync 检索custom contact store中指定contact remote ID的Contacts,取得IAsyncOperation<StoredContact>的集合。
? GetChangesAsync 获取变更与所提供的版本号相关联的联系人存储的列表。
回传值为:IAsyncOperation<IVectorView>
? LoadExtendedPropertiesAsync 为custom contact store载入扩充的属性集合。
回传值:IAsyncOperation<IDictionary>。
该方法被用於针对contact store载入扩充的属性,而不是针对个别的contact。

常见情境即是用於有的contact store加入延伸的属性,利用revision number来与remote contact store进行同步,取得extension properties来加入既有的contact store。
? SaveExtendedPropertiesAsync 储存新提供的name/value清单至custom contact store的扩充属性。
SaveExtendedPropertiesAsync( IReadOnlyDictionary<String, Object> data ) 。

???

?

StoredContact

??? 代表关联於custom contact store的contact物件。相关的建构子、方法与属性说明如下:

类型 名称 说明
Constructor StoredContact(ContactStore) 初始化StoredContact类别的实体。
? StoredContact(ContactStore, ContactInformation) 初始化StoredContact类别的实体,并给予具有初始化相关属性的ContactInformation物件。
Method GetDisplayPictureAsync 取得stored contact的显示图像。
? GetExtendedPropertiesAsync 取得stored contact的扩充属性集合,采用name/value pairs呈现。
? GetPropertiesAsync 取得contact已知的属性集合。
? ReplaceExistingContactAsync 利用目前的StoredContact取代指定ID的contact。
? SaveAsync 储存目前StoedContact的状态与属性至contact store。
? SetDisplayPictureAsync 使用IInputStream object设定contact的显示图像。
? ToVcardAsync() 采用vCard 3.0 format来将contact加以表示。
? ToVcardAsync(VCardFormat) 采用特定vCard format来将contact加以表示。
Property DisplayName Read/write。设定/取得stored contact的显示名称。
? DisplayPicture Read-only。取得stored contact的显示图像。
? FamilyName Read/write。设定/取得stored contact的家庭名称。
? GivenName Read/write。设定/取得stored contact的特定名称。
? HonorificPrefix Read/write。设定/取得stored contact的honorific prefix(敬语前缀)。
? HonorificSuffix Read/write。设定/取得stored contact的honorific suffix(敬语後缀)。
? Id Read-only。取得stored contact的local identifier(该值由系统自动给予)。
? RemoteId Read/write。设定/取得stored contact的remote identifier。
? Store Read-only。取得stored contact所储存的ContactStore。其值在StoredContact建构子时就会被给予。

要使用StoredContact时预先要取得ContactStore,另外StoredContact是利用 local id(来自系统给予)与 remote id来加以管理,

利用remote + local id来建立关联电话中的contact与cloud上的contact;所以App里如果要管理自订义的Contact可给予唯一的

RemoteId来予後端的系统资料加以对应。

如果要操作的联络人资讯未被储存於ContactStore或StoredContact,可藉由ContactInformation加以描述来使用。

?

?

以上说明完重要的类别与方法後,往下便藉由范例的方式来说明如何加以运用。

?

[范例]

该范例的情境,例如:

a. 做一个App专属於某家公司的零件维修人员专用;

b. App自动会建立专属的联络人,用户不需要手动建立;

c. 专属联络人的资料由後端系统维护;

?

了解该范例的情境後,以下分成几个步骤来加以介绍操作的方式:

?

A. 建立後端联络人资料档案(以XML档为例),负责管理StoredContact.RemoteId;

<?xml version="1.0" encoding="utf-8" ?>

<contacts version="1">

  <contact rid="10000" dname="jenna" fname="wang" gname="jenna" prefix="" suffix="">

    <picture>https://fbcdn-sphotos-f-a.akamaihd.net/hphotos-ak-prn1/t1/75603_10153754407645367_493094653_n.jpg?dl=1</picture>

    <mphone>0932111222</mphone>

    <mail>jenna@live.com</mail>

    <jobtitle>Actor</jobtitle>

  </contact>

  <contact rid="10001" dname="安心亚" fname="" gname="" prefix="" suffix="">

    <picture>https://fbcdn-sphotos-e-a.akamaihd.net/hphotos-ak-prn2/t1/1502517_10153643531660467_768374391_n.jpg?dl=1</picture>

    <mphone>0932111222</mphone>

    <mail>annie@live.com</mail>

    <jobtitle>Actor</jobtitle>

  </contact>

  <contact rid="10002" dname="Zooey Deschanel" fname="Deschanel" gname="" prefix="" suffix="">

    <picture>http://images.artistdirect.com/Images/nad/video/tribune/65426/65426_bc.jpg</picture>

    <mphone>0932111123</mphone>

    <mail>zooey@live.com</mail>

    <jobtitle>Actor</jobtitle>

  </contact>

  <contact rid="10003" dname="Natalie Portman" fname="" gname="" prefix="" suffix="">

    <picture>http://beauty.nownews.com/img/27/i26127-24.jpg</picture>

    <mphone>0932147699</mphone>

    <mail>portman@live.com</mail>

    <jobtitle>Actor</jobtitle>

  </contact>

</contacts>

??? 以上是使用XML的方式建立了联络人的资讯,当然如果具有自行管理的联络人系统就可以不用这样麻烦。

??? 该范例把建立好的XML档放置至於网路空间:Skydrvie或Dropbox均可以。

?

?

B. 建立一个画面专门用於同步与汇入远端联络人资料档;

??? b-1. XAML:

<!--TitlePanel contains the name of the application and page title-->

<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">

    <TextBlock Text="ContactStore Project" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>

    <TextBlock Text="同步" 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">

    <StackPanel>

        <Button Content="点击同步" Click="Button_Click" />

        <TextBlock x:Name="tblTile" Text="同步状态" Margin="15,5,5,10" />

        <toolkit:WrapPanel Width="450" Height="300">

            <TextBlock TextWrapping="Wrap"

                       x:Name="tblResultMsg"

                       Width="440" Height="300"

                       Margin="5"  />

        </toolkit:WrapPanel>

        <Button Content="操作Contact Store" Click="Button_Click_1" />

    </StackPanel>

</Grid>

?

???? b-2. 在OnNavigationTo初始化ContactStore物件;

private ContactStore gMyCStore = null;

?

protected async override void OnNavigatedTo(NavigationEventArgs e)

{

    base.OnNavigatedTo(e);

?

    // 进行必要元件的初始化

    if (gMyCStore == null)

    {

        gMyCStore = await ContactStore.CreateOrOpenAsync();

        // 可搭配对应的AsscessMode来初始化ContactStore。

        //gMyCStore = await ContactStore.CreateOrOpenAsync(

        //                        ContactStoreSystemAccessMode.ReadWrite,

        //                        ContactStoreApplicationAccessMode.ReadOnly);

    }

}

?

???? b-3. 建立按钮事件来触发 下载联络人资料档案的任务;

private void Button_Click(object sender, RoutedEventArgs e)

{

    // 下载远端的联络人资料档案

    string tURL = "";

?

    HttpWebRequest tRequest = HttpWebRequest.CreateHttp(tURL);

    tRequest.BeginGetResponse((IAsyncResult ar) =>

    {

        if (ar.IsCompleted)

        {

            HttpWebResponse tResponse = 

                (HttpWebResponse)tRequest.EndGetResponse(ar);

            if (tResponse.StatusCode == HttpStatusCode.OK)

            {

                using (StreamReader tResponseStream = 

                        new StreamReader(tResponse.GetResponseStream()))

                {

                    string strResult = tResponseStream.ReadToEnd();

                    XDocument tXDoc = XDocument.Parse(strResult);

?

                    // 识别是否需要进行更新

                       bool tIsNeedUpdate = true;

                    if (IsolatedStorageSettings.ApplicationSettings.Contains("cs_v") == true)

                    {

                        double tV = double.Parse(

                                IsolatedStorageSettings.ApplicationSettings["cs_v"].ToString());

                        var tNVersoin = double.Parse(tXDoc.Root.Attribute("version").Value);

                        if (tNVersoin <= tV) tIsNeedUpdate = false;

                    }

                    if (tIsNeedUpdate)

                    {

                        // 进行更新

                        FeedDataToContactStore(tXDoc);

                    }

                }

            }

        }

    }, tRequest);

}

??????????? 上述程式除了完成下载联络人资料档之外,也做了版本的比对,这样一来只要管理後端的资料档,

??????????? 等用户按下同步,App就可以取得最新的资料档案进行更新了。

?

???? b-4. 负责汇入联络人资料至ContactStore;

/// <summary>

/// 将远端联络人资讯更新至本地的ContactStore。

/// </summary>

/// <param name="pXDoc"></param>

private async void FeedDataToContactStore(XDocument pXDoc)

{

    try

    {

        var tDataSet = from CItem in pXDoc.Descendants().Elements("contact")

                        select CItem;

        // 遂一更新既有的联络人

        foreach (XElement tCItem in tDataSet)

        {

            StoredContact tCObj = null;

            // 先识别指定的Id是否已经存在了,才不会重覆加入StoredContact

            tCObj = await gMyCStore.FindContactByRemoteIdAsync(tCItem.Attribute("rid").Value);

            if (tCObj == null)

            {

                // 代表指定的RemoteId不存在於custom ContactStore

                tCObj = new StoredContact(gMyCStore);

                tCObj.RemoteId = tCItem.Attribute("rid").Value;

            }

          

            // 填入必要的参数

            tCObj.DisplayName = tCItem.Attribute("dname").Value;

            tCObj.FamilyName = tCItem.Attribute("fname").Value;

            tCObj.GivenName = tCItem.Attribute("gname").Value;

            tCObj.HonorificPrefix = tCItem.Attribute("prefix").Value;

            tCObj.HonorificSuffix = tCItem.Attribute("suffix").Value;

?

            // 利用GetPropertiesAsync填入已知的联络人资讯

            IDictionary<string, object> props = await tCObj.GetPropertiesAsync();

            if (props.ContainsKey(KnownContactProperties.Email))

                props[KnownContactProperties.Email] = tCItem.Element("mail").Value;

            else

                props.Add(KnownContactProperties.Email, tCItem.Element("mail").Value);

            if (props.ContainsKey(KnownContactProperties.MobileTelephone))

                props[KnownContactProperties.MobileTelephone] = tCItem.Element("mphone").Value;

            else

                props.Add(KnownContactProperties.MobileTelephone, tCItem.Element("mphone").Value);

            if (props.ContainsKey(KnownContactProperties.JobTitle))

                props[KnownContactProperties.JobTitle] = tCItem.Element("jobtitle").Value;

            else

                props.Add(KnownContactProperties.JobTitle, tCItem.Element("jobtitle").Value);

?

            // 增加扩充的属性描述

            IDictionary<string, object> extprops = await tCObj.GetExtendedPropertiesAsync();

            if (extprops.ContainsKey("Provider") == false)

                extprops.Add("Provider", "Pou Mason - ContactStoreProj");

?

            // 填入呈现的图像

            try

            {

                HttpWebRequest tRequest = HttpWebRequest.CreateHttp(tCItem.Element("picture").Value);

                tRequest.BeginGetResponse(async (IAsyncResult ar) =>

                {

                    if (ar.IsCompleted)

                    {

                        HttpWebResponse tResponse = (HttpWebResponse)tRequest.EndGetResponse(ar);

                        if (tResponse.StatusCode == HttpStatusCode.OK)

                        {

                            await tCObj.SetDisplayPictureAsync(tResponse.GetResponseStream().AsInputStream());

                            // 由於是不同的thread,所以要再使用一次SaveAsync()

                            await tCObj.SaveAsync();

                        }

                    }

                }, tRequest);

            }

            catch (Exception) { }

?

            // 储存至ContactStore

            await tCObj.SaveAsync();

?

            // 更新进度

            Dispatcher.BeginInvoke(() =>

            {

                tblTile.Text += string.Format("\nname: {0}, \t{1}", tCObj.DisplayName, "success");

            });

        }

    }

    catch (Exception ex)

    {

        Dispatcher.BeginInvoke(() =>

        {

            tblTile.Text += ex.Message;

        });    

    }            

}

??????????? 上述程式根据取得的XML资料加以汇入至ContactStore,每一个<contact />搭配一个rid的唯一值来对应ContactStore

??????????? 中的StoredContact物件,加以识别是否具有存在的Properties与ExtendedProperties,并采用非同步设定它的DisplayPicture。

?

??????????? [注意]

??????????? a. 里面使用了HttpWebRequest的并没有做最佳化的处理,所以当大量资料汇入时可能会有问题。

??????????? b. 采用非同步下载图像资料时,由於与汇入基本资料属於不同的Thread,所以要设定二次的SaveAsync()。?

??????????? c. 如果在撰写汇入资料至ContactStore太久时,建议可以分批同步,可搭配Backgroun Agent的方式来定期分批汇入;??

?

至步骤B就完成了汇入联络人至ContactStore的任务,以下为执行的画面:

?

透过上图可以得知自行App所建立的ContactStore对於People Hub也是一个筛选的资料来源,因此,

如果用户安装了你的App之後一定会发现不认识的联络人增加了很多,此时,可以在App给一些提示告知他们如果隐藏这些联络人:

可至「设定->应用程式->联络人->筛选我的联络人清单」,取消勾选该App的资源来源。

?

?

C. 搜寻指定的联络人

???? c-1. 定义搜寻的画面:

<!--ContentPanel - place additional content here-->

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

    <Grid.RowDefinitions>

        <RowDefinition Height="13*" />

        <RowDefinition Height="25*" />

        <RowDefinition Height="62*" />

    </Grid.RowDefinitions>

    <TextBox Grid.Row="0" x:Name="txtName" />

    <StackPanel Grid.Row="1">

        <Button Content="Query" x:Name="btnQuery" Click="btnQuery_Click" />

        <Button Content="Delete" x:Name="btnDelete" Click="btnDelete_Click" />

    </StackPanel>

    <ListBox x:Name="lstContact" Grid.Row="2">

        <ListBox.ItemTemplate>

            <DataTemplate>

                <StackPanel Orientation="Horizontal" Margin="15">

                    <Border BorderThickness="2"

                            HorizontalAlignment="Left"

                            BorderBrush="{StaticResource PhoneAccentBrush}" >

                        <Image Source="{Binding Converter={StaticResource ContactPictureConverter}}" 

                               Width="80" Height="60" 

                               Stretch="Fill" />

                    </Border>

                    <StackPanel Margin="5">

                        <TextBlock Text="{Binding Path=DisplayName, Mode=OneWay}" VerticalAlignment="Center" />

                        <TextBlock Text="{Binding Path=FamilyName, Mode=OneWay}" VerticalAlignment="Center" />

                        <TextBlock Text="{Binding Path=RemoteId, Mode=OneWay}" VerticalAlignment="Center" />

                    </StackPanel>

                </StackPanel>

            </DataTemplate>

        </ListBox.ItemTemplate>

    </ListBox>

</Grid>

?

???? c-2. 定义了IValueConvert负责将StoredContact中的DisplyPicture转换成WriteableBitmap;

/// <summary>

/// 客制一个转换联络人图片的类别,透过实作IValueConverter Interface覆写指定转换的功能。

/// </summary>

public class ContactPictureConverter : IValueConverter

{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        if (value == null) return null;

?

        StoredContact tC = value as StoredContact;

        // 取得DisplayPciture的值,采用Task的方式取代await的使用方法,强迫执行序等待

        var tTask = tC.GetDisplayPictureAsync().AsTask();

        tTask.Wait();

        // 将取得的IRandomAccessStream转换成Steam并建立成WriteableBitmap

        WriteableBitmap tWbmap = Microsoft.Phone.PictureDecoder.DecodeJpeg(tTask.Result.AsStream());

?

        return tWbmap;

    }

?

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        throw new NotImplementedException();

    }

}

?????????? 由於DisplyPicture的取得需采用非同步的方式,依照过去的写法一定会加上await,但这样会让IValueConvert无法识别回传值,

?????????? 所以没有办法直接使用async + await的方式。因此,这篇改用直接将await转换成一个Task的物件,并且强迫该Task进行等待

?????????? 等待取得图像IRandomAccessStream後,最後再转换成WriteableBitmap回传至Image物件。

?????????? 详细内容参考<XAML Image From Path>。

?

???? c-3. 定义搜寻的逻辑:

private async void btnQuery_Click(object sender, RoutedEventArgs e)

{

    // 建立一个ContactQueryResult

    ContactQueryResult tResultObj = gMyCStore.CreateContactQuery();

?

    // 也可以搭配指定要搜寻的项目

    //ContactQueryOptions tOptions = new ContactQueryOptions();

    //tOptions.DesiredFields.Add(KnownContactProperties.Email);

    //tOptions.OrderBy = ContactQueryResultOrdering.SystemDefault;

    //ContactQueryResult tResultObj = gMyCStore.CreateContactQuery(tOptions);

?

    // 取得目前ContactStore中有联络人的数量

    uint tCount = await tResultObj.GetContactCountAsync();

?

    // 取得目前所有的联络人集合

    IReadOnlyList<StoredContact> tContacts = await tResultObj.GetContactsAsync();

?

    // 根据输入的文字搜寻StoredContact

    IEnumerable<StoredContact> tSearch = tContacts.Where(x => x.DisplayName.Contains(txtName.Text));

?

    lstContact.ItemsSource = tSearch;

}

??????????? 配合ContactQueryResult的物件取得目前在ContactStore中所具有的所有StoredContact,并搭配LINQ进行搜寻。

?

D. 删除指定联络人的资料

private async void btnDelete_Click(object sender, RoutedEventArgs e)

{

    if (lstContact.SelectedIndex != -1)

    {

        StoredContact tContact = lstContact.SelectedItem as StoredContact;

        // 必须使用StoredContact.Id (local id),因为该值是由系统给予的。

        await gMyCStore.DeleteContactAsync(tContact.Id);

?

        MessageBox.Show("移除成功!");

?

        ContactQueryResult tResultObj = gMyCStore.CreateContactQuery();

        lstContact.ItemsSource = await tResultObj.GetContactsAsync();

    }

}

??? 根据选择指定的StoredContact,取得它的Id(local Id)指定给ContactStore来进行删除。

?

看一下执行的画面与结果:

?

E. 搭配vCard的处理:

??? 可参考<How to perform basic custom contact store operations for Windows Phone - ?Saving a contact from a vCard>

?

以上即是介绍如何操作自行建立的ContactStore。

?

[范例程式]

使用该范例程式时,记得先将里面的RemoteContact.xml档案放至Dropbox或其他免费空间,并更换b-3中的tURL变数才有办法正常使用喔。

======

该篇文章我觉得对於如果您想要做App与People Hub加上整合或是扩充现有联络人的功能,

可以详细去了解其中的运作原理,这样可以让你的App更加的强力。

希望解释的还算清楚对大家有所帮助。

?

References

?Custom contact store for Windows Phone

?How to perform basic custom contact store operations for Windows Phone

?Building a Custom Contact Store in Your Windows Phone 8 Application

?Using the Windows Phone Custom Contact Store

?How to display the photo of a contact for Windows Phone

?Contact filtering and matching for Windows Phone & Contacts.SearchAsync Method

?Convert XML to Object using LINQ

?《深入浅出Windows Phone 8应用开发》之程序联系人存储

?Tag Archives: convert Stream to IRandomAccessStream

?Display Image from Stream in Windows 8 and Windows Phone 8

?Using User-Provided Images for Secondary Tiles

?Set display picture of StoredContact from byte[]

?与众不同 windows phone (39) - 8.0 联系人和日历

?Drawing / Inking API in WinRT (C#) – II

?

Dotblogs 的标签:Windows Phone

enjoy developing application and learning new technology time.

DotBlogs Tags:

Windows Phone

posted on
2014/2/13 16:09
|

我要推荐

|
阅读数 : 392

| 文章分类 [

Windows Phone

]

|
订阅

Windows Phone 8 - 建立App专属联络人资讯(ContactStore)的更多相关文章

  1. eclipse Maven 使用记录 ------ 建立app项目

    maven 项目构建工具 , 如今已逐渐取代ant的笨拙配置方式 ,使项目管理更加简单,规范,结构更加清晰,这里记录跟eclipse集成的一些步骤  1.从apache maven项目下下载maven ...

  2. [转]windows 软链接的建立及删除

    [转]windows 软链接的建立及删除 http://blog.chinaunix.net/uid-74941-id-3764093.html 1.建立举例 ##建立d:develop链接目录,指向 ...

  3. Windows 8.1 store app 开发笔记

    原文:Windows 8.1 store app 开发笔记 零.简介 一切都要从博彦之星比赛说起.今年比赛的主题是使用Bing API(主要提到的有Bing Map API.Bing Translat ...

  4. Python之建立APP流程以及SVN 的使用

    一, 1)我们先拿到SVN的地址比如说:https://123.com/trunck/nihao 2)执行命令行 svn checkout 此时check out是将项目存到了本地根目录下面,如果想存 ...

  5. Thunder——爱阅app(测评人:方铭)

    B.Thunder——爱阅app(测评人:方铭) 一.基于NABCD评论作品,及改进建议 每个小组评论其他小组Alpha发布的作品: 1.根据(不限于)NABCD评论作品的选题: 2.评论作品对选题的 ...

  6. Github for Windows使用图文教程_西西软件资讯

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  7. windows 下 Django 搭架子 - 从建立project到建立app

    第一步,安装python 3.6 到C:\Python,在Python官网下Windows版的安装包即可 安装Django,在命令行下直接 pip install django,django 被安装在 ...

  8. Windows 7如何建立一个FTP的快捷方式

    原来,使用Windows XP的时候,在IE6的地址栏里输入FTP服务器的地址,就可以打开一个资源管理器的界面来管理文件.但是,随着IE的版本的提升或是装了Windows 7,原来的这种方法就不能用了 ...

  9. Windows下快速建立cocos2d-x项目

    准备工作     1.根据当前系统版本,下载对应版本的Python         32位下载地址:http://www.python.org/ftp/python/2.7.5/python-2.7. ...

随机推荐

  1. 在WPF的WebBrowser控件中抑制脚本错误

    原文:在WPF的WebBrowser控件中抑制脚本错误 今天用WPF的WebBrowser控件的时候,发现其竟然没有ScriptErrorsSuppressed属性,导致其到处乱弹脚本错误的对话框,在 ...

  2. perl 访问网站一些useragent的设置

    121.40.205.143 - - [22/Jun/2016:12:56:23 +0800] "GET /wechat/account.html HTTP/1.1" 200 34 ...

  3. poj3621 Sightseeing Cows --- 01分数规划

    典型的求最优比例环问题 參考资料: http://blog.csdn.net/hhaile/article/details/8883652 此题中,给出每一个点和每条边的权值,求一个环使 ans=∑点 ...

  4. queue C++

    #include <iostream> using namespace std; class DequeEmptyException { public: DequeEmptyExcepti ...

  5. Rudiments 0.42 发布,C++ 常用工具包 - 开源中国社区

    Rudiments 0.42 发布,C++ 常用工具包 - 开源中国社区 Rudiments 0.42 发布,C++ 常用工具包

  6. 做SEO所要具备的四种能力

    1,不为失败找借口         既然我们选择了做SEO,那么发生网站被降权.被K是常常的事.当这样的情况发生时,大部分站长首先将责任推给百度机制,由于百度更新算法调整遭降权,不是由于他们的优化没有 ...

  7. 应用层open(read、write、close)怎样调用驱动open(read、write、close)函数的?

    应用层open(read.write.close)怎样调用驱动open(read.write.close)函数的? 华清远见2014-09-29   北京海淀区 张俊浩 三大数据结构关系图

  8. HDU 2255 奔小康,赚钱(KM算法模板)

    解决问题的思路: 二部图,正确的匹配,卡费用流,使用KM算法. #include <cstring> #include <algorithm> #include <cst ...

  9. hdu1054(最小顶点覆盖)

    传送门:Strategic Game 题意:用尽量少的顶点来覆盖所有的边. 分析:最小顶点覆盖裸题,最小顶点覆盖=最大匹配数(双向图)/2. #include <cstdio> #incl ...

  10. libevent book——event | Gaccob的博客

    libevent book——event | Gaccob的博客 libevent book——event 发表于 2013 年 2 月 22 日 由 gaccob 原文地址:http://www.w ...