我的问题是:
我有一个WPF文本框绑定在属性Filter上。它作为一个过滤器工作:每次TextBox.Text更改时,都会设置Filter属性。
<TextBox Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}" />
现在在ViewModel上有我的Filter属性:每次过滤器改变时,我更新我的值。
private string _filter;
public string Filter
{
get { return _filter; }
set
{
_filter = value;
// call to an async WEB API to get values from the filter
var values = await GetValuesFromWebApi(_filter);
DisplayValues(values);
}
}
public async Task<string> GetValuesFromWebApi(string query)
{
var url = $"http://localhost:57157/api/v1/test/result/{query}";
// this code doesn't work because it is not async
// return await _httpClient.GetAsync(url).Result.Content.ReadAsStringAsync();
// better use it this way
var responseMessage = await _httpClient.GetAsync(url);
if (responseMessage.IsSuccessStatusCode)
{
return await responseMessage.Content.ReadAsStringAsync();
}
else
{
return await Task.FromResult($"{responseMessage.StatusCode}: {responseMessage.ReasonPhrase}");
}
}
由于不允许使用异步属性,如果绑定需要调用异步方法,我该怎么做才能使它工作呢?
3条答案
按热度按时间ilmyapht1#
我将假设DisplayValues方法实现正在更改绑定到UI的属性,并且为了进行演示,我将假设它是一个
List<string>
:它是绑定:
现在,正如您所说的,不允许使属性setter异步,因此我们必须使其同步,我们可以做的是将Values属性更改为某种类型,该类型将隐藏其数据来自异步方法的事实,作为实现细节,并以同步方式构造此类型。
Stephen Cleary的Mvvm.Async库中的
NotifyTask
将帮助我们实现这一点,我们要做的是将Values属性更改为:并更改其绑定:
这样,我们创建了一个属性,该属性表示为数据绑定定制的
Task
相似类型,包括忙碌指示符和错误传播,以及有关this MSDN articale中NotifyTask
用法的更多信息(注意,NotifyTask
在那里被视为NotifyTaskCompletion
)。现在,最后一部分是更改Filter属性setter,以便在每次更改筛选器时,使用相关的异步操作将notifyValuesTask设置为新的
NotifyTask
(无需await
任何内容,所有监视都已嵌入NotifyTask
中):您还应该注意到GetValuesFromWebApi方法会阻塞,这会使您的UI冻结,您不应该在调用
GetAsync
后使用Result
属性,而是使用await
两次:dvtswwa32#
你可以这样做。注意在“async void”中你需要处理所有的异常。如果你不这样做,应用程序可能会崩溃。
j91ykkif3#
这在一个属性设置器中工作&我使用它:
为清楚起见,使用async方法: