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

详细信息:我有一个名为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;
    }
}

当前回答

为了在构造函数中使用async,并确保实例化类时数据可用,可以使用以下简单的模式:

class FooClass : IFooAsync
{        
    FooClass 
    {
        this.FooAsync = InitFooTask();
    }

    public Task FooAsync { get; }

    private async Task InitFooTask()
    {
        await Task.Delay(5000);
    }
}

的接口:

public interface IFooAsync
{
    Task FooAsync { get; }
}

的用法:

FooClass foo = new FooClass();    
if (foo is IFooAsync)
    await foo.FooAsync;

其他回答

你可以试试AsyncMVVM。

Page2.xaml:

<PhoneApplicationPage x:Class="Page2"
                      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <ListView ItemsSource="{Binding Writings}" />
</PhoneApplicationPage>

Page2.xaml.cs:

public partial class Page2
{
    InitializeComponent();
    DataContext = new ViewModel2();
}

ViewModel2.cs:

public class ViewModel2: AsyncBindableBase
{
    public IEnumerable<Writing> Writings
    {
        get { return Property.Get(GetWritingsAsync); }
    }

    private async Task<IEnumerable<Writing>> GetWritingsAsync()
    {
        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");
            yield return writing;
        }
    }
}

为了在构造函数中使用async,并确保实例化类时数据可用,可以使用以下简单的模式:

class FooClass : IFooAsync
{        
    FooClass 
    {
        this.FooAsync = InitFooTask();
    }

    public Task FooAsync { get; }

    private async Task InitFooTask()
    {
        await Task.Delay(5000);
    }
}

的接口:

public interface IFooAsync
{
    Task FooAsync { get; }
}

的用法:

FooClass foo = new FooClass();    
if (foo is IFooAsync)
    await foo.FooAsync;

如果你想让它等待任务完成,你可以改进madlars代码如下。(我尝试了。net core 3.1,它工作)

var taskVar = Task.Run(async() => await someAsyncFunc());

taskVar.Wait();

简单地说,参考斯蒂芬·克利里https://stackoverflow.com/a/23051370/267000

创建页面时应该在构造函数中创建任务,并且应该将这些任务声明为类成员或将其放入任务池中。

你的数据在这些任务期间被获取,但这些任务应该在代码中等待,即在一些UI操作上,即Ok单击等。

我在WP中开发了这样的应用程序,我们一开始就创建了一大堆任务。

有点晚了,但我认为很多人都在努力解决这个问题……

我也一直在找这个。为了让你的方法/动作运行异步而不等待或阻塞线程,你需要通过SynchronizationContext来排队,所以我想出了这个解决方案:

我为它做了一个辅助类。

public static class ASyncHelper
{

    public static void RunAsync(Func<Task> func)
    {
        var context = SynchronizationContext.Current;

        // you don't want to run it on a threadpool. So if it is null, 
        // you're not on a UI thread.
        if (context == null)
            throw new NotSupportedException(
                "The current thread doesn't have a SynchronizationContext");

        // post an Action as async and await the function in it.
        context.Post(new SendOrPostCallback(async state => await func()), null);
    }

    public static void RunAsync<T>(Func<T, Task> func, T argument)
    {
        var context = SynchronizationContext.Current;

        // you don't want to run it on a threadpool. So if it is null, 
        // you're not on a UI thread.
        if (context == null)
            throw new NotSupportedException(
                "The current thread doesn't have a SynchronizationContext");

        // post an Action as async and await the function in it.
        context.Post(new SendOrPostCallback(async state => await func((T)state)), argument);
    }
}

使用/例子:

public partial class Form1 : Form
{

    private async Task Initialize()
    {
        // replace code here...
        await Task.Delay(1000);
    }

    private async Task Run(string myString)
    {

        // replace code here...
        await Task.Delay(1000);
    }

    public Form1()
    {
        InitializeComponent();

        // you don't have to await nothing.. (the thread must be running)
        ASyncHelper.RunAsync(Initialize);
        ASyncHelper.RunAsync(Run, "test");

        // In your case
        ASyncHelper.RunAsync(getWritings);
    }
}

这适用于Windows。表单和WPF