总结:我想在构造函数中调用异步方法。这可能吗?

详细信息:我有一个名为getwritings()的方法,用于解析JSON数据。如果我只是在异步方法中调用getwritings()并将await放在它的左边,那么一切都可以正常工作。然而,当我在我的页面中创建一个LongListView并试图填充它时,我发现getWritings()令人惊讶地返回null, LongListView为空。

为了解决这个问题,我尝试将getWritings()的返回类型更改为Task<List<Writing>>,然后通过getWritings(). result在构造函数中检索结果。然而,这样做最终会阻塞UI线程。

public partial class Page2 : PhoneApplicationPage
{
    List<Writing> writings;

    public Page2()
    {
        InitializeComponent();
        getWritings();
    }

    private async void getWritings()
    {
        string jsonData = await JsonDataManager.GetJsonAsync("1");
        JObject obj = JObject.Parse(jsonData);
        JArray array = (JArray)obj["posts"];

        for (int i = 0; i < array.Count; i++)
        {
            Writing writing = new Writing();
            writing.content = JsonDataManager.JsonParse(array, i, "content");
            writing.date = JsonDataManager.JsonParse(array, i, "date");
            writing.image = JsonDataManager.JsonParse(array, i, "url");
            writing.summary = JsonDataManager.JsonParse(array, i, "excerpt");
            writing.title = JsonDataManager.JsonParse(array, i, "title");

            writings.Add(writing);
        }

        myLongList.ItemsSource = writings;
    }
}

当前回答

试着替换一下:

myLongList.ItemsSource = writings;

用这个

Dispatcher.BeginInvoke(() => myLongList.ItemsSource = writings);

其他回答

在任何构造函数中执行一些耗时操作的快速方法是创建一个动作并异步运行它们。

new Action( async() => await InitializeThingsAsync())();

运行这段代码既不会阻塞UI,也不会留下任何松散的线程。如果您需要更新任何UI(考虑到您没有使用MVVM方法),您可以像许多人建议的那样使用Dispatcher进行更新。

注意:如果你没有任何init或onload或导航覆盖,这个选项只提供了一种从构造函数开始执行方法的方法。最有可能的是,即使在建设完成后,它仍将继续运行。因此,此方法调用的结果可能在构造函数本身中不可用。

您可以将异步调用放在单独的方法中,并在构造函数中调用该方法。 尽管如此,这可能会导致某些变量值在您期望它们的时候不可用。

 public NewTravelPageVM(){
   GetVenues();              
 }

 async void  GetVenues(){
   var locator = CrossGeolocator.Current;
   var position = await locator.GetPositionAsync();
   Venues = await Venue.GetVenues(position.Latitude, position.Longitude);
 }

布莱恩·拉古纳斯展示了一个我非常喜欢的解决方案。更多信息,他的youtube视频

解决方案:

添加一个TaskExtensions方法

  public static class TaskExtensions
{
    public static async void Await(this Task task, Action completedCallback = null ,Action<Exception> errorCallBack = null )
    {
        try
        {
            await task;
            completedCallback?.Invoke();
        }
        catch (Exception e)
        {
            errorCallBack?.Invoke(e);
        }
    }
}

用法:

  public class MyClass
{

    public MyClass()
    {
        DoSomething().Await();
       // DoSomething().Await(Completed, HandleError);
    }

    async Task DoSomething()
    {
        await Task.Delay(3000);
        //Some works here
        //throw new Exception("Thrown in task");
    }

    private void Completed()
    {
        //some thing;
    }

    private void HandleError(Exception ex)
    {
        //handle error
    }

}

试着替换一下:

myLongList.ItemsSource = writings;

用这个

Dispatcher.BeginInvoke(() => myLongList.ItemsSource = writings);

我喜欢的方法是:

// caution: fire and forget
Task.Run(async () => await someAsyncFunc());