假设我有一个长时间运行的Web API调用(异步方法),它返回一个字符串。
这两个解决方案之间是否有最佳实践可以在不阻止UI的情况下在WPF属性中显示结果?或者还有另一个吗?
注意:这两个解决方案都没有冻结用户界面,我已经查看了帖子How to call an async method from a getter or setter?和Async property in c#。
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}" />
视图模型:
public MyConstructor()
{
Task task = SetAsyncPropertyA();
}
private async Task SetAsyncPropertyA()
{
this.AsyncPropertyA = await GetAsyncProperty().ConfigureAwait(false);
}
XAML:
<TextBlock Text="{Binding Path=AsyncPropertyB, UpdateSourceTrigger=PropertyChanged, IsAsync=True, FallbackValue='Loading B...'}" />
视图模型:
public string AsyncPropertyB
{
get
{
return GetAsyncPropertyB();
}
}
private string GetAsyncPropertyB()
{
return Task.Run(() => GetAsyncProperty()).Result;
}
注意:在解决方案B中,我可以添加在解决方案A中不起作用的FallbackValue,以及可能在Task.Run的ContinueWith中的其他一些UI更新。
答案 0 :(得分:4)
你应该尝试使用一个好的框架,它已经投入了那个轮子。
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 => )
答案 1 :(得分:2)
在这两种情况下,您都没有捕获尝试调用Web API时可能发生的任何错误。您可能希望将其记录到文件和/或向用户显示错误消息。
在这种情况下,await让它变得简单 - 你可以使用try / catch:
Public Class daDbContext
Inherits System.Data.Entity.DbContext
Public Property MyTable() As DbSet(Of MyTable)
Public Sub New(con As OracleConnection)
MyBase.New(CType(con, DbConnection), contextOwnsConnection:=True)
End Sub
End Class
您还可以将try / catch移动到异步方法。在这种情况下,因为没有错误从它逃脱,你可以使它异步无效。有时这对于事件处理程序是必要的(至少在Windows窗体中 - 不确定WPF。)
Try
Dim con As New OracleConnection("Data Source=mydb;Password=mypassword;Persist Security Info=True;" + _
"User ID=myuser;Connection Lifetime=0;Connection Timeout=15;HA Events=false;" + _
"Load Balancing=false;Max Pool Size=100;Min Pool Size=1;Pooling=false;" + _
"Validate Connection=false")
con.Open()
' Try to read data with our connection'
Dim com As OracleCommand = con.CreateCommand()
com.CommandText = "SELECT * FROM mytable"
Dim reader As OracleDataReader = com.ExecuteReader()
While reader.Read()
Console.WriteLine("new connection: " + DirectCast(reader("mycolumn"), String))
' Works fine..'
End While
' Init ef-db-context'
Dim ctx As New daDbContext(con)
' Try to read Data with connection from ef-db-context'
com = DirectCast(ctx.Database.Connection.CreateCommand(), OracleCommand)
com.CommandText = "SELECT * FROM mytable"
reader = com.ExecuteReader()
While reader.Read()
Console.WriteLine("ctx connection: " + DirectCast(reader("mycolumn"), String))
' Works fine..'
End While
' Throws exception'
Dim l As List(Of MyTable) = ctx.MyTable.ToList()
Console.WriteLine(l.First().MyColumn)
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try