CommandManager.RequerySuggested是如何工作的?

47

MSDN仅说明:

在CommandManager检测到可能更改命令执行能力的条件时发生。

但是我似乎找不到任何关于它如何工作、我应该注意什么/避免什么等方面的线索......它只是监听输入吗?(例如鼠标移动、按键等)

2个回答

54

我无法准确告诉您CommandManager监听的事件。 但是,我可以告诉您,在与异步操作一起使用CommandManager时应该< strong>小心。 当我在我的ICommand实现中使用CommandManager时,出现了以下问题:

我有一个绑定到ICommand的按钮,触发异步操作增加一个值。 现在,如果该值达到特定限制,则应禁用按钮/ ICommand(即其CanExecute()方法应返回false)。 问题是: CommandManager在按钮被点击并启动异步操作后立即调用我的CanExecute()方法。这个异步操作不需要很长时间,但足以在CommandManager的检查之后获取其结果,因此在CanExecute()中进行的限制检查使用的是旧值。 因此,按钮仍然启用,尽管实际上已经达到了限制。 有趣的是,当您单击界面上的任何位置后,按钮现在会被禁用,因为CommandManager再次检查ICommand,并且现在将新值与限制进行了比较。 实际上,我认为CommandManager在按钮单击后等待约50毫秒才执行ICommand检查,但我不太确定。

我的解决方案是在收到异步操作的结果后立即通过在ViewModel中调用CommandManager.InvalidateRequerySuggested方法来强制CommandManager再次检查ICommand
更新:请注意,此方法必须在UI线程上调用,否则它将无效! (感谢midspace的评论)


13
需要注意的是,由于您正在运行异步调用,因此必须在UI线程中调用CommandManager.InvalidateRequerySuggested(),否则根据个人经验,它将不起作用。 - midspace
4
在这种情况下,我认为你不应该仅使用CommandManager.RequerySuggested作为CanExecuteChanged事件的触发器。显然,您的代码知道异步操作何时完成,应该利用这个完成来触发命令的CanExecuteChanged。可能CommandManager.RequerySuggested也有很好的想法,因此您可以在此基础上做出补充。 - RichardHowells

5
如果是这种情况,.NET参考源代码会是你的好帮手。尽管它没有很好的注释,但你仍然可以获得一些有关内部处理的想法。
在内部CommandDevice类中,你会找到一个名为PostProcessInput的方法,它调用了InvalidateRequerySuggested。假设这个方法的名称是每次输入事件都会被调用,我相信还会有进一步的处理和过滤,以便你的CanExecute方法实际上不会在每次调用InvalidateRequerySuggested时被调用。

该URL已更改为https://referencesource.microsoft.com/#PresentationCore/Core/CSharp/System/Windows/Input/Command/CommandDevice.cs (我无法提交编辑,因为它涉及少于6个字符)。 - Mike Rosoft
1
@MikeRosoft,我已经完成了你的更改。 - StayOnTarget

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接