等待异步调用完成

时间:2016-03-06 03:00:24

标签: c# asynchronous async-await win-universal-app

我正在使用飞利浦Hue,我需要先从色调网桥获取一些信息,然后才能填充我的应用程序。请求通过HTTP / JSON进行。我运行所有代码async时没有问题,但是当我尝试分解我的代码以便在加载时我有一个单独的方法来更新UI我得到System.NullReferenceException在myLights上。我假设这是因为startUpProcedure()尚未完成,因此myLights尚未设置。在运行startUpProcedure()之前,我似乎无法弄清楚如何等待setupUI()完成。

为了进一步支持这一点,如果我只是在没有startUpProcedure()的情况下运行setupUI(),我就不会有任何问题。然后,如果我从一个按钮单击运行setupUI(),它就会运行得很好。

显然,我在这里遗漏了一些东西。我似乎无法找到答案。

所以简洁地提出一个问题:我如何等待这些异步调用完成,以便我可以使用依赖于它们的返回值的变量?

 public sealed partial class MainPage : Page
 {

    public string appKey;
    public string myIP;
    public IEnumerable<Light> myLights;
    public ILocalHueClient myClient;

    public MainPage()
    {
        this.InitializeComponent();

        startUpPocedure();


        setupUI();

    }

    public async Task startUpPocedure()
    {
        await startUp();

        await getLights();
    }

    public async Task startUp()
    {
        if (await findBridgeIP())
        {
            Debug.WriteLine("Bridge Found...");
            //Do Actions
        }
        else
        {
            //Error!!
            Debug.WriteLine("No hue found");
        }

        Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
        Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;

        try {
            appKey = localSettings.Values["appKey"].ToString();

            Debug.WriteLine("appKey loaded: " + appKey);

            //Load up 
            myClient = new LocalHueClient(myIP);

            myClient.Initialize(appKey);

        }
        catch {
            Debug.WriteLine("Need to register app");
        }

    }

    async Task getLights()
    {

        myLights = await myClient.GetLightsAsync();

        Debug.WriteLine("Light Count " + myLights.Count());

        IEnumerable<string> myLightNames;

        List<string> myTempList = new List<string>();

        foreach (Light l in myLights)
        {
            myTempList.Add(l.Name);
            Debug.WriteLine(l.Name);
        }

        myLightNames = myTempList;

        comboBox_LightSelect.ItemsSource = myLightNames;

    }

    private void setupUI()
    {
        //Populate the Combo Box
        IEnumerable<string> myLightNames;

        List<string> myTempList = new List<string>();

        foreach (Light l in myLights)
        {
            myTempList.Add(l.Name);
            Debug.WriteLine(l.Name);
        }

        myLightNames = myTempList;

        comboBox_LightSelect.ItemsSource = myLightNames;


    }

2 个答案:

答案 0 :(得分:1)

您的MainPage构造函数中的startUpPocedure方法几乎立即返回任务,并且由于您没有等待它,代码执行会在此之后立即进入下一行并调用setupUI。因此,当您的代码开始枚举myLights集合时,它仍然为空,因为startUpPocedure因此getLights仍在运行。

问题是,您无法在构造函数中等待异步方法,因此在您的情况下,解决方案是将startUpPoceduresetupUI移动到单个异步方法,等待它们在此方法中并调用它来自类似的构造函数:

public MainPage()
{
    this.InitializeComponent();    
    Startup();        
}

private async void Startup()
{
    await startUpPocedure();   
    setupUI();
}

答案 1 :(得分:1)

您应该只在构造函数中留下InitializeComponent,并将所有其他逻辑移到Loaded事件处理程序,

https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.frameworkelement.loaded

然后,您可以将该处理程序标记为async,并在其中使用await等待异步方法。