I now have no problem with the People/Contacts displaying as I was having - several times in a row now they have all displayed - but the call to retrieve a Contacts object never returns - with the breakpoint on this line:
var contact = await contactPicker.PickSingleContactAsync();
...I never get there - although I am able to choose a Contact and then select the "Select" button. Control never switches from the Emulator to the breakpoint.
For full disclosure, here is the entire method:
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");
}
So why does the call to PickSingleContactAsync() never return?
UPDATE
All the buttons of a certain functionality share an OnClick handler (I should have come into the 21.08th century and used the OnTapped handler); this handler calls the async method like so:
Task<System.Collections.Generic.KeyValuePair<string, string>> kvpContactNameEmail = SelectAContactForASlot();
UPDATE 2
Okay, now I'm really bamboozled:
This code, in the button 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);
. . .
...does get past the call to SelectAContactForASlot() -- stepping through the first line returns immediately -- but it returns before the People/Contact Picker displays. And so, there is no key or value in the KVP, since SelectAContactForASlot(), which it is returning from, is supposed to return that:
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;
}
...and for some reason, the People/Contact picker displays (assuming I have clicked btn1_1) on reaching this line:
ApplicationData.Current.LocalSettings.Values["PersonSection1Slot1"] = kvpContactNameEmail.Result.Key;
...but still, nothing is actually returned, because it stalls on the line:
var contactPicker = new Windows.ApplicationModel.Contacts.ContactPicker();
So SelectAContactForASlot() is getting called later than I thought it would/should, but once it does get called, it fails to proceed.
UPDATE 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;
}
UPDATE 4
...and if I change my buttonClick code to:
private async void PersonButton_OnClick(object sender, RoutedEventArgs args)
{
Task<System.Collections.Generic.KeyValuePair<string, string>> kvpContactNameEmail = await SelectAContactForASlot();
. . .
(added "async" and "await" here), I get, "Cannot implicitly convert type 'System.Collections.Generic.KeyValuePair' to 'System.Threading.Tasks.Task>'"
I guess my problem really is that I don't want the call to SelectAContactForASlot() to return until it retrieves the contact object (the Contact app is invoked and the user selects a Contact); IOW, I want it to be asynchronous. But I don't think there is an async version of PickSingleContactAsync() - IOW, there's no "PickSingleContact".
So what I really want to know is: how can I invoke the Contact app and allow the user to select a Contact (already doing that) and get back values from that object that I can then access in my code? Obviously I'm going about this all wrong.