如何获得异步调用的结果?

时间:2020-04-22 08:49:16

标签: c# uwp

我有一个切换语言助手,写得像

public static async Task SelectLanguage()
{
    //Some extra code
    string strTitle = await LanService.Get("select_language");
    ListDialogControl dialog = new ListDialogControl(strTitle, list, index);
    dialog.Show();
    dialog.Result += async (s) =>
    {

        **//How to pass this returned  variable s to SelectLanguage()**
    };
}

现在我想将SelectLanguage()从Task更改为Task《字符串》,这将返回对话框的结果。

对于ListDialogControl,它是一个用户控件。

public sealed partial class ListDialogControl : UserControl
{
    Popup popup;
    int ListSelectedIndex;
    List<string> myList = new List<string>();

    public Action<string> Result { get; set; }

    /// <summary>
    /// Title
    /// List<string>
    /// selectedIndex, -1 no need to select.  if u want to select an item, selectedIndex must >= 0
    /// </summary>
    /// <param name="strTitle"></param>
    /// <param name="list"></param>
    /// <param name="selectedIndex"></param>
    public ListDialogControl(string strTitle, List<string> list, int selectedIndex = -1, bool showTick = true)
    {
        this.InitializeComponent();

        popup = Globals.popup;
        popup.Child = this;
        popup.Closed += Popup_Closed;
        this.Loaded += ControlWindow_Loaded;
        this.Unloaded += ControlWindow_Unloaded;
        this.PreviewKeyDown += ControlWindow_PreviewKeyDown;
        Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += Dispatcher_AcceleratorKeyActivated;

        this.Width = Window.Current.Bounds.Width;
        this.Height = Window.Current.Bounds.Height;

        TextBlockTip.Text = strTitle;
        myList = list;
    }

    #region ShowHide
    public void Show()
    {
        popup.IsOpen = true;
    }

    public void Hide(string result)
    {
        if (popup.IsOpen == false)
            return;

        popup.IsOpen = false;
        myList.Clear();
        TextBlockTip.Text = "";
        Result?.Invoke(result);
    }
    #endregion
}

2 个答案:

答案 0 :(得分:2)

您可以使用TaskCompletionSource来达到目的。这是两种实现方法。请务必阅读有关此文档,以确保您知道如何处理不同的states of a task

选项1:在方法内使用TaskCompletionSource

public static async Task SelectLanguage()
{
    var tcs = new TaskCompletionSource<string>(); 

    ListDialogControl dialog = new ListDialogControl(strTitle, list, index);
    dialog.Show();
    dialog.Result += async (s) =>
    {
        // This will notify the caller that the task just completed
        tcs.SetResult(s);
    };

    // Here you can wait until the task completes
    var yourResult = await tcs.Task;
}

选项2:在UserControl中使用TaskCompletionSource

public class YourUserControl : UserControl
{
    private TaskCompletionSource<string> _resultTask;

    public Task<string> Show()
    {
        _resultTask = new TaskCompletionSource<string>();
        return _resultTask.Task;
    }

    public void Hide(string result)
    {
        _resultTask.SetResult(result);
    }
}

现在您无需每次都创建TaskCompletionSource:

public async Task TestMethod()
{
    var dialog = new YourUserControl();

    // Show dialog and wait here until the usercontrol completes the task
    var result= await dialog.Show();
}

答案 1 :(得分:1)

使用TaskCompletionSource的另一种方法是使用SemaphoreSlim异步等待,直到您有返回值:

public static async Task<string> SelectLanguage()
{
    string strTitle = await LanService.Get("select_language");
    string result = null;
    using (SemaphoreSlim semaphore = new SemaphoreSlim(0, 1))
    {
        ListDialogControl dialog = new ListDialogControl(strTitle, list, index);
        dialog.Show();
        dialog.Result += async (s) =>
        {
            //...
            result = s;
            semaphore.Release();
        };
        await semaphore.WaitAsync();
    }
    return result;
}
相关问题