我想在Xamarin.Forms中把async方法链接到prism框架中的一个delegate命令,我的问题是怎么做?
以下解决方案是否正确?是否存在任何缺陷?(死锁、UI缓慢或冻结、不良实践...)
{ // My view model constructor
...
MyCommand = new DelegateCommand(async () => await MyJobAsync());
...
}
private async Task MyJobAsync()
{
... // Some await calls
... // Some UI element changed such as binded Observable collections
}
7条答案
按热度按时间db2dz4w81#
You can use
async void
directly. However, a few notes from my experience...The structure of your code is: start asynchronous operation and then update UI with the results. This implies to me that you would be better served with a
NotifyTask<T>
kind of approach to asynchronous data binding, not commands. See my async MVVM data binding article for more about the design behindNotifyTask<T>
(but note that the latest code has a bugfix and other enhancements).If you really do need an asynchronous command (which is much more rare), you can use
async void
directly or build an async command type as I describe in my article on async MVVM commmands . I also have types to support this but the APIs for these are more in flux.If you do choose to use
async void
directly:async Task
logic public, or at least accessible to your unit tests.DelegateTask
, any exceptions from your delegate must be properly handled.tvokkenx2#
Just have a look at this link if you're using Prism Library: https://prismlibrary.com/docs/commands/commanding.html#implementing-a-task-based-delegatecommand
In case you want to pass a
CommandParameter
toDelegateCommand
, use in theDelegateCommand
variable declaration this syntaxIn the constructor of the ViewModel initialize it this way:
where
HandleTap
is declared asHope it helps.
wljmcqd83#
正如已经提到的,用delegate命令处理异步代码的方法是使用
async void
,对此已有很多讨论,远远超出了仅仅是棱镜或Xamarin形式。底线是ICommand
,Command
和棱镜DelegateCommand
都受到ICommand
的void Execute(object obj)
的限制。如果你'I“我想了解更多有关这方面的信息,我鼓励您阅读Brian Lagunas的博客,其中解释了为什么DelegateCommand.FromAsync
handler is obsolete。一般来说,大多数问题都可以通过更新代码来轻松解决。例如,我经常听到关于
Exceptions
的抱怨,因为Exceptions
是FromAsync必不可少的“原因”,结果却发现他们的代码中从来没有try catch。因为async void
是“发射后忘记,”我听到的另一个抱怨是一个命令可能执行两次。这个问题也很容易用DelegateCommands
、ObservesProperty
和ObservesCanExecute
解决。2cmtqfgy4#
我认为从一个同步执行的方法(ICommand.Execute)调用一个异步方法时的两个主要问题是1)在前一个调用仍在运行时拒绝再次执行2)异常处理。这两个问题都可以通过如下的实现(原型)来解决。这将是DelegateCommand的异步替代。
异步空值
我个人会不惜一切代价避免“async void”。从外部不可能知道操作何时完成,错误处理变得棘手。关于后者,例如编写一个从“async void”方法调用的“async Task”方法,几乎需要知道它的失败Task是如何传播的:
然后有人在另一天写:
vfwfrxfs5#
是的,UI线程运行
DelegateCommand
。如果是async
线程,它将运行到第一个await
语句,然后恢复其常规UI线程工作。如果将等待器配置为捕获同步上下文(即,您 * 不 * 使用.ConfigureAwait(false)
),则UI线程将在await
之后继续运行DelegateCommand
。UI线程是否运行DelegateCommand ,后台线程是否运行await表达式?
“await表达式”是在后台线程、前台线程、线程池线程还是其他线程上运行取决于您调用的api。例如,您可以使用
Task.Run
将CPU绑定的工作推送到线程池,或者您可以使用Stream.ReadAsync
等方法等待i/o操作,而根本不使用任何线程xoefb8l86#
wgmfuz8q7#
There are no pitfalls. A void return type in async method was created especially for delegates. If you want to change something, that has reflected on UI, insert relevant code in this block:
Actually, ICommand and DelegateCommand pretty similar, so an above answer is quite right.