3

私が持っていたように、People/Contacts が表示されることに問題はありません-数回続けてすべて表示されました - しかし、Contacts オブジェクトを取得するための呼び出しは返されません - この行にブレークポイントがあります:

var contact = await contactPicker.PickSingleContactAsync();

...連絡先を選択して [選択] ボタンを選択することはできますが、そこにたどり着きません。コントロールがエミュレータからブレークポイントに切り替わることはありません。

完全な開示のために、ここにメソッド全体があります:

private async Task<System.Collections.Generic.KeyValuePair<string, string>> SelectAContactForASlot()
{
    KeyValuePair<string, string> kvp;
    var contactPicker = new Windows.ApplicationModel.Contacts.ContactPicker();
    contactPicker.CommitButtonText = "Select";
    var contact = await contactPicker.PickSingleContactAsync();
    if (contact != null)
    {
        kvp = new KeyValuePair<string, string>(contact.Name, contact.Emails[0].Value);
        if (null != kvp.Value) // If there is no email, there's no use in passing it back, as the person cannot be contacted
        {
            return kvp;
        }
        else
        {
            return kvp = new KeyValuePair<string, string>(contact.Name, "No email found");
        }
    }
    return kvp = new KeyValuePair<string, string>("No Name found", "No email found");
}

では、PickSingleContactAsync() の呼び出しが返されないのはなぜでしょうか?

アップデート

特定の機能のすべてのボタンは、OnClick ハンドラーを共有します (21.08 世紀に入って、OnTapped ハンドラーを使用する必要がありました)。このハンドラーは、次のように async メソッドを呼び出します。

Task<System.Collections.Generic.KeyValuePair<string, string>> kvpContactNameEmail = SelectAContactForASlot();

更新 2

さて、私は本当にだまされています:

ボタン Onclick 内のこのコード:

private void PersonButton_OnClick(object sender, RoutedEventArgs args)
{
    Task<System.Collections.Generic.KeyValuePair<string, string>> kvpContactNameEmail = SelectAContactForASlot();
    Button btn = null;
    if (args.OriginalSource is Button)
    {
        btn = args.OriginalSource as Button;
    }
    if (null == btn)
    {
        return;
    }
    //btn1_1 to btn3_4
    if (btn.Name == "btn1_1")
    {
        ApplicationData.Current.LocalSettings.Values["PersonSection1Slot1"] = kvpContactNameEmail.Result.Key;
        btn1_1.Foreground = new SolidColorBrush(Windows.UI.Colors.Gray);
    . . .

... SelectAContactForASlot () の呼び出しを通過します -- 最初の行をステップ実行するとすぐに戻ります -- しかし、People/Contact Picker が表示される前に戻ります。そのため、KVP にはキーまたは値がありません。これは、それが返される SelectAContactForASlot() がそれを返すことになっているためです。

    private async Task<System.Collections.Generic.KeyValuePair<string, string>> SelectAContactForASlot()
    {
            KeyValuePair<string, string> kvp;
            var contactPicker = new Windows.ApplicationModel.Contacts.ContactPicker();
            contactPicker.CommitButtonText = "Select";
            var contact = await contactPicker.PickSingleContactAsync();
            if (contact == null)
            {
                kvp = new KeyValuePair<string, string>("No Name found", "No email found");
            }
            else // contact != null
            {
                if (string.IsNullOrWhiteSpace(contact.Emails[0].Value))
                {
                    kvp = new KeyValuePair<string, string>(contact.Name, "No email found");
                }
                else
                {
                    kvp = new KeyValuePair<string, string>(contact.Name, contact.Emails[0].Value);
                }
            }
            return kvp;
}

...そして何らかの理由で、人/連絡先ピッカーが次の行に到達すると表示されます (btn1_1 をクリックしたと仮定します):

ApplicationData.Current.LocalSettings.Values["PersonSection1Slot1"] = kvpContactNameEmail.Result.Key;

...しかし、実際には何も返されません。行で停止するためです。

var contactPicker = 新しい Windows.ApplicationModel.Contacts.ContactPicker();

したがって、 SelectAContactForASlot() は、思ったよりも遅く呼び出されていますが、呼び出されると、続行できません。

更新 3

    private void PersonButton_OnClick(object sender, RoutedEventArgs args)
    {
        Task<System.Collections.Generic.KeyValuePair<string, string>> kvpContactNameEmail = SelectAContactForASlot();
    . . .

    private async Task<KeyValuePair<string, string>> SelectAContactForASlot()
    {
        KeyValuePair<string, string> kvp;
        var contactPicker = new Windows.ApplicationModel.Contacts.ContactPicker();
        contactPicker.CommitButtonText = "Select";
        var contact = await contactPicker.PickSingleContactAsync();
        if (contact == null)
        {
            kvp = new KeyValuePair<string, string>("No Name found", "No email found");
        }
        else // contact != null
        {
            if (string.IsNullOrWhiteSpace(contact.Emails[0].Value))
            {
                kvp = new KeyValuePair<string, string>(contact.Name, "No email found");
            }
            else
            {
                kvp = new KeyValuePair<string, string>(contact.Name, contact.Emails[0].Value);
            }
        }
        return kvp;
    }

更新 4

...そして、buttonClick コードを次のように変更すると:

private async void PersonButton_OnClick(object sender, RoutedEventArgs args)
{
    Task<System.Collections.Generic.KeyValuePair<string, string>> kvpContactNameEmail = await SelectAContactForASlot();
    . . .

(ここに「async」と「await」を追加)、「型 'System.Collections.Generic.KeyValuePair' を 'System.Threading.Tasks.Task>' に暗黙的に変換できません」と表示されます

私の問題は、連絡先オブジェクトを取得するまで SelectAContactForASlot() への呼び出しを返さないことだと思います (連絡先アプリが呼び出され、ユーザーが連絡先を選択します)。IOW、非同期にしたい。しかし、PickSingleContactAsync() の非同期バージョンはないと思います - IOW、「PickSingleContact」はありません。

だから私が本当に知りたいのは、連絡先アプリを呼び出して、ユーザーが連絡先を選択できるようにし (既にそれを行っている)、コードでアクセスできるそのオブジェクトから値を取得できるようにするにはどうすればよいかということです。明らかに、私はこれについてすべて間違っています。

4

2 に答える 2

3

呼び出し階層のある時点で、Task返された bySelectAContactForASlotまたはそれを呼び出すメソッドをブロックしていると思います。

SelectAContactForASlotこれは、完了時に UI コンテキストで再開する必要がawaitあり、UI スレッドが完了を待機してブロックされるため、デッドロックが発生SelectAContactForASlotします。

このデッドロックを回避するには、次のようにorを使用する代わりに s を使用awaitする必要があります。TaskWaitResult

private async void PersonButton_OnClick(object sender, RoutedEventArgs args)
{
  KeyValuePair<string, string> kvpContactNameEmail = await SelectAContactForASlot();
  ...
}

このシナリオについては、私のブログで詳しく説明しています。

于 2012-11-22T19:15:03.020 に答える
0

Update 2 コードで、次の行を変更します。

Task<System.Collections.Generic.KeyValuePair<string, string>> kvpContactNameEmail = SelectAContactForASlot();

このため:

Task<System.Collections.Generic.KeyValuePair<string, string>> kvpContactNameEmail = SelectAContactForASlot().AsTask();
KeyValuePair<string, string> tempKeyValuePair = FileTask.Result;

説明: あなたがしているのは、非同期の世界を同期の世界にバインドすることです。元の呼び出しは Task を取得するだけで、タスクが終了するのを待つのではなく、何もしません (そのため、呼び出しは即座に返されます)。

于 2012-11-23T20:35:55.300 に答える