WPF异步属性的最佳实践



让我们假设我有一个长期运行的Web API调用(async方法),该调用返回字符串。

这两个解决方案之间是否有最佳实践在不阻止UI的情况下显示结果?还是还有另一个?

注意:两种解决方案都不冻结UI,我已经查看了如何从Getter或Setter调用异步方法的帖子?和c#中的异步属性。

我的WEP API

private async Task<string> GetAsyncProperty()
{
    string result = "Async Property Value";
    // Web api call...
    await Task.Delay(TimeSpan.FromSeconds(10));
    return result;
}

解决方案

xaml:

<TextBlock Text="{Binding Path=AsyncPropertyA, UpdateSourceTrigger=PropertyChanged}" />

ViewModel:

public MyConstructor()
{
    Task task = SetAsyncPropertyA();
}
private async Task SetAsyncPropertyA()
{
    this.AsyncPropertyA = await GetAsyncProperty().ConfigureAwait(false);
}

解决方案B

xaml:

<TextBlock Text="{Binding Path=AsyncPropertyB, UpdateSourceTrigger=PropertyChanged, IsAsync=True, FallbackValue='Loading B...'}" />

ViewModel:

public string AsyncPropertyB
{
    get
    {
        return GetAsyncPropertyB();
    }
}
private string GetAsyncPropertyB()
{
    return Task.Run(() => GetAsyncProperty()).Result;
}

注意:在解决方案B中,我可以添加在解决方案A中不起作用的后备值,并且可能在任务继续进行的其他UI更新。

在两种情况下,您都不会遇到任何尝试调用Web API时可能发生的错误。您可能需要将其记录到文件和/或向用户显示错误消息。

在这种情况下,等待变得容易 - 您可以使用try/catch:

public MyConstructor()
{
    try
    {
        Task task = SetAsyncPropertyA();
    }
    catch (Exception e)
    {
        // log the error or show a message
    }
}
private async Task SetAsyncPropertyA()
{
    this.AsyncPropertyA = await GetAsyncProperty().ConfigureAwait(false);
}

您也可以将尝试/捕获移动到异步方法。在这种情况下,由于没有错误逃脱的机会,因此您可以使其异步无效。有时,这对于事件处理程序(至少在Windows表单中 - 不确定WPF)是必需的。)

public MyConstructor()
{
    SetAsyncPropertyA();
}
private async void SetAsyncPropertyA()
{
    try
    {
        this.AsyncPropertyA = await GetAsyncProperty().ConfigureAwait(false);
    }
    catch (Exception e)
    {
        // log the error or show a message
    }
}

您应该尝试为此使用一个好的框架,该框架已经开启了。

查看reactiveui命令示例:

LoadTweetsCommand = ReactiveCommand.CreateAsyncTask(() => LoadTweets())
LoadTweetsCommand.ToProperty(this, x => x.TheTweets, out theTweets);
LoadTweetsCommand.ThrownExceptions.Subscribe(ex => /* handle exception here */);

这些扩展程序在iObservable上起作用,这本身就是非常强大的工具:

Observable.FromAsync(async () =>
            {
                await Task.Delay(100);
                return 5;
            }).ToProperty(x => )

最新更新