我有一个带有蒙皮切换按钮的Windows Phone客户端,它充当了“收藏夹”按钮。然后,checked属性与ViewModel(标准MVVM模式)双向绑定。
<ToggleButton IsChecked="{Binding DataContext.IsFavouriteUser, ElementName=PageRoot, Mode=TwoWay}">
当更改绑定布尔值时,我想启动对服务的异步网络调用。
public bool IsFavouriteUser
{
get { return _isFavouriteUser; }
set
{
if (SetProperty(ref _isFavouriteUser, value))
{
// Dispatches the state change to a RESTful service call
// in a background thread.
SetFavouriteState();
}
}
}
如果用户多次按下该按钮,则可以进行许多添加/删除异步服务调用 - 假设这些需要2秒钟来进行网络往返和服务处理。
过去我使用过类似的东西:
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
// I would probably dispatch this call to a background thread in the real client
public async Task<bool> SetFavouriteState()
{
try
{
await _semaphore.WaitAsync();
bool result;
if (IsFavouriteUser)
{
result = await ServiceClient.AddAsync(x);
}
else
{
result = await ServiceClient.RemoveAsync(x);
}
return result;
}
catch
{
// I wouldn't use an empty catch in production code
return false;
}
finally
{
_semaphore.Release();
}
}
然而,这可能无休止地排队用户输入;而该服务仅对最新的用户事件感兴趣 - 开启或关闭 - 并且UI应保持对用户输入的响应。
答案 0 :(得分:2)
有几种很好的模式可以处理异步重入,即如果用户操作在其已经在飞行中时调用异步方法会发生什么。我在这里写了几篇文章:
我认为您的问题是模式5(下面的代码)的一个特例。
但是,请注意您的规格中的一个奇怪之处。用户可能会足够快地点击以获得序列“添加”,然后是“添加”(例如,如果介入的“删除”在第二次单击“添加到达”之前甚至没有机会开始执行)。因此,请以您自己的方案特定方式防止这种情况发生。
async Task Button1Click()
{
// Assume we're being called on UI thread... if not, the two assignments must be made atomic.
// Note: we factor out "FooHelperAsync" to avoid an await between the two assignments.
// without an intervening await.
if (FooAsyncCancellation != null ) FooAsyncCancellation.Cancel();
FooAsyncCancellation = new CancellationTokenSource ();
FooAsyncTask = FooHelperAsync(FooAsyncCancellation.Token);
await FooAsyncTask;
}
Task FooAsyncTask;
CancellationTokenSource FooAsyncCancellation;
async Task FooHelperAsync( CancellationToken cancel)
{
try { if (FooAsyncTask != null ) await FooAsyncTask; }
catch ( OperationCanceledException ) { }
cancel.ThrowIfCancellationRequested();
await FooAsync(cancel);
}
async Task FooAsync( CancellationToken cancel)
{
...
}
答案 1 :(得分:0)
我建议在触发请求时禁用ToggleButton
按钮并显示不确定的ProgressBar
并隐藏ProgressBar
并在完成时启用ToggleButton
。