等待异步调用完成

问题描述:

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

为了进一步说明这一点,如果我只是在没有setupUI()的情况下运行startUpProcedure(),则不会出现问题。然后,如果我运行setupUI()从说按钮点击它运行得很好。

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

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

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; 


    } 

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

问题是,你不能等待异步方法在一个构造函数,所以你的情况的解决方案将是既startUpPoceduresetupUI移动到单一异步方法,等待他们这种方法中,并从类似这样的构造函数中调用它:

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

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

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

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

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