试图让方法等待内部事件处理完成

时间:2013-11-07 20:18:09

标签: c# .net windows-phone-8 task-parallel-library async-await

我是C#async / await的新手,在尝试使用异步方法时遇到了一些问题。 我有一个集合:

private IList<IContactInfo> _contactInfoList

和异步方法:

public async Task<IList<IContactInfo>> SelectContacts()
{
    _contactInfoList = new List<IContactInfo>();
    ContactsSelector selector = new ContactsSelector();
    selector.ShowPicker();

    selector.ContactsSelected += (object sender, ContactsSelectorEventArgs e) =>
    {
        this._contactInfoList = e.Contacts;                
    };

    return _contactInfoList;
}

联系人选择器是一个弹出式用户控件,允许从手机中选择一些联系人,点击“确定”按钮后会触发ContactsSelected事件。我需要从事件参数e.Contacts中获取所选联系人列表,并在上面提到的SelectContacts()异步方法中返回该列表。问题出在这里:我的方法在_contactInfoList事件完成工作之前已经返回空列表ContactsSelected。我知道在这种情况下async / await甚至无关紧要,并且这个问题将存在于通常的方法中,但我只需要使该方法等待事件处理结果。

1 个答案:

答案 0 :(得分:4)

您需要做的是将异步编程的事件样式转换为异步编程的任务样式。 TaskCompletionSource的使用使这相当简单。

public static Task<IList<IContactInfo>> WhenContactsSelected(
    this ContactsSelector selector)
{
    var tcs = new TaskCompletionSource<IList<IContactInfo>>();
    selector.ContactsSelected += (object sender, ContactsSelectorEventArgs e) =>
    {
        tcs.TrySetResult(e.Contacts);
    };
    return tcs.Task;
}

既然我们有一个方法可以返回一个我们需要的结果的任务,那么使用它的方法非常简单:

public Task<IList<IContactInfo>> SelectContacts()
{
    ContactsSelector selector = new ContactsSelector();
    selector.ShowPicker();

    return selector.WhenContactsSelected();
}

这里有几点需要注意。首先,我删除了实例字段;这似乎是一个坏主意。如果多次调用SelectContacts,则会导致两个人争夺该字段。逻辑上,如果您确实需要存储列表,它应该是一个局部变量。接下来,此处没有await用途,因此该方法不应标记为async。如果您想await拨打WhenContactsSelected,请随时重新添加async,但截至目前,我认为没有真正的需要。