1

在 Twitter 上,Justin Angel 暗示能够解决已知的 Windows Phone SDK 限制,您无法启动显示给定联系人详细信息的 ShowContactTask(在此处投票解决此问题)。我自己进行了一个测试以尝试使其正常工作,但它只显示一个带有用户名的空白页面。

有人有机会举例说明如何进行这项工作吗?

提前致谢!

4

1 回答 1

4

正如我在推特上所说,WP8 不允许从自定义启动器任务或通过 app2app 自定义协议启动联系人详细信息。

人员中心确实支持在与联系人详细信息屏幕非常相似的屏幕中导入 vCard。您可以使用此功能主要导入 vCard 或选择性地显示联系人详细信息(即使它会显示为新联系人)。这是人员中心的 vCard app2app 文件关联:

  <Extensions>
    <FileTypeAssociation Name="VCard" Category="phone.fileTypeAssociation" TaskID="ViewVCardContact" NavUriFragment="VCardMode=2&amp;vCardFileToken=%s">
      <Logos>
        <Logo Size="small" IsResource="true">res://ContactsRes{ScreenResolution}!VCard.FileTypeIcon.Small.png</Logo>
        <Logo Size="medium" IsResource="true">res://ContactsRes{ScreenResolution}!VCard.FileTypeIcon.Medium.png</Logo>
        <Logo Size="large" IsResource="true">res://ContactsRes{ScreenResolution}!VCard.FileTypeIcon.Large.png</Logo>
      </Logos>
      <SupportedFileTypes>
          <FileType ContentType="text/vcard">.vcf</FileType>
          <FileType ContentType="text/x-vcard">.vcf</FileType>
      </SupportedFileTypes>
    </FileTypeAssociation>
  </Extensions>

为了使用这个 app2app 自定义协议,我们可以编写一些代码来创建 vCard VCF 文件,将其保存到 IsoStore 并在人员中心启动 vCard。

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    var contacts = new Contacts();
    contacts.SearchCompleted += contacts_SearchCompleted;
    contacts.SearchAsync(string.Empty, FilterKind.None, null);
}

private async void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
{
    // get a Contact and build a vCard for it
    Contact contact = e.Results.First();
    string vcard = GetContactVCard(contact);
    Debug.WriteLine(vcard);

    // write the vCard to IsoStore as a VCF file
    using (var s = IsolatedStorageFile.GetUserStoreForApplication().CreateFile("myContact.vcf"))
    using (var sw = new StreamWriter(s))
    {
        sw.Write(vcard);
    }

    // launch the VCF file 
    var vcardStorageFile = await ApplicationData.Current.LocalFolder.GetFileAsync("myContact.vcf");
    Launcher.LaunchFileAsync(vcardStorageFile);
}

接下来我们必须实现构建 vCard 的函数。我们将使用 vCard 3.0 版,因为我们需要 Base64 嵌入式图像(稍后会详细介绍)。我从 Wikipedia 复制了 vCard 3.0 格式,因此这个示例没有任何 Microsoft 特定的扩展。我只是将 vCard 复制到代码中,并从 Contact 类中输入了一些数据。

    private string GetContactVCard(Contact contact)
        {
            return string.Format(@"BEGIN:VCARD
VERSION:3.0
N:{0};{1}
FN:{2}
ORG:{3}
TITLE:{4}
PHOTO;TYPE=PNG;ENCODING=B:{9}
TEL;TYPE=WORK,VOICE:{5}
TEL;TYPE=HOME,VOICE:{6}
ADR;TYPE=WORK:;;{10}
ADR;TYPE=HOME:;;{11}
EMAIL;TYPE=PREF,INTERNET:{7}
REV:{8}
END:VCARD",
          contact.CompleteName.LastName,
          contact.CompleteName.FirstName,
          contact.DisplayName,
          contact.Companies.Any() ? contact.Companies.First().CompanyName : string.Empty,
          contact.CompleteName.Title,
          contact.PhoneNumbers.Any(p => p.Kind == PhoneNumberKind.Work) ? contact.PhoneNumbers.First(p => p.Kind == PhoneNumberKind.Work).PhoneNumber : string.Empty,
          contact.PhoneNumbers.Any(p => p.Kind != PhoneNumberKind.Work) ? contact.PhoneNumbers.First(p => p.Kind != PhoneNumberKind.Work).PhoneNumber : string.Empty,
          contact.EmailAddresses.Any() ? contact.EmailAddresses.First().EmailAddress : string.Empty,
          DateTime.Now.ToFileTimeUtc(),
          GetPhotoBase64(contact),
          contact.Addresses.Any(a => a.Kind == AddressKind.Home) ? BuildAddress(contact.Addresses.First(a => a.Kind == AddressKind.Home).PhysicalAddress) : string.Empty,
          contact.Addresses.Any(a => a.Kind == AddressKind.Work) ? BuildAddress(contact.Addresses.First(a => a.Kind == AddressKind.Work).PhysicalAddress) : string.Empty
            );
        }

你可以看到我并没有花太多时间完善这个逻辑。如果您添加一些边缘条件处理并可能移动到 StringBuilder 可能是最好的。接下来我们将构建更复杂的地址字符串:

private string BuildAddress(CivicAddress physicalAddress)
{
    StringBuilder sb = new StringBuilder();

    string[] address = new string[]
                       {
                           physicalAddress.AddressLine1,
                           physicalAddress.AddressLine2,
                           physicalAddress.City + " " + physicalAddress.StateProvince,
                           physicalAddress.CountryRegion,
                           physicalAddress.PostalCode
                       };

    foreach (var line in address)
        if (!string.IsNullOrEmpty(line))
            sb.Append(line + ";");

    return sb.ToString();
}

最后,我们需要将图像嵌入到我们的 vCard 中。我们在 base64 中嵌入了联系人照片,因为 WP8 没有可用于该联系人照片的 URL。

private string GetPhotoBase64(Contact contact)
{
    using (var picture = contact.GetPicture())
    {
        if (picture == null)
        {
            return null;
        }
        else
        {
            using (var sr = new StreamReader(picture))
            {
                byte[] data = new byte[picture.Length];
                picture.Read(data, 0, data.Length);
                return Convert.ToBase64String(data);
            }
        }
    }
}

当我们运行此代码片段时,我们可以看到它将联系人属性的大部分详细信息传递到导出/导入的 vCard 中:

vCard 导入 - 屏幕 #1 vCard 导入 - 屏幕 #2

于 2013-01-01T04:28:18.927 回答