我在WPF中采用MVVM模式并学习了Command
的使用。但是在我的实现中,我总是调用我分配给实现CanExecute
的委托。我的意思是如果我在委托函数中放置一个断点,它表明这个函数不断被调用。根据我的理解(以及一种自然的思维方式,但当然我可能是错的),只有当我以某种方式通知状态的变化时才会调用此委托,而CommandManager
(重新)检查{{ 1}}属性并修改UI元素的CanExecute
属性。
这是我对VB.NET的实现,我最初是从C#版本获得的。我注意到我需要对移植的代码进行一些更改才能进行编译。难道它是C#和VB.NET的底层是不同的?那么有人可以为我提供一个原始的VB.NET实现,或者指出我有什么问题,或者如果我正确理解Command行为会怎么做?
这是我的VB.NET版本:
IsEnabled
我如何实例化一个对象是这样的:
Public Class CommandBase
Implements ICommand
Public Property ExecuteDelegate() As Action(Of Object)
Public Property CanExecuteDelegate() As Predicate(Of Object)
Public Sub New()
End Sub
Public Sub New(execute As Action(Of Object))
Me.New(execute, Nothing)
End Sub
Public Sub New(execute As Action(Of Object), canExecute As Predicate(Of Object))
If execute Is Nothing Then
Throw New ArgumentNullException("execute")
End If
ExecuteDelegate = execute
CanExecuteDelegate = canExecute
End Sub
Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
Return If(CanExecuteDelegate Is Nothing, True, CanExecuteDelegate(parameter))
End Function
Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
AddHandler(ByVal value As EventHandler)
If CanExecuteDelegate IsNot Nothing Then
AddHandler CommandManager.RequerySuggested, value
End If
End AddHandler
RemoveHandler(ByVal value As EventHandler)
If CanExecuteDelegate IsNot Nothing Then
RemoveHandler CommandManager.RequerySuggested, value
End If
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
CommandManager.InvalidateRequerySuggested()
End RaiseEvent
End Event
Public Sub Execute(parameter As Object) Implements ICommand.Execute
If ExecuteDelegate IsNot Nothing Then ExecuteDelegate.Invoke(parameter)
End Sub
Public Sub RaiseCanExecuteChanged()
CommandManager.InvalidateRequerySuggested()
End Sub
End Class
当然CanExecuteExec的签名如下:
MyCommand = New CommandBase(AddressOf CommandExec, AddressOf CanExecuteExec)
就像我提到的那样,Private Function CanExecuteExec(obj As Object) As Boolean
一直在被召唤。我想这是低效的,想象我有数百个CanExecuteExec
个对象,而且大多数Command
个对象在大多数情况下都不会被改变。
有人说CanExecute
确实一直被召唤,而其他人却反其道而行之。我不是这方面的专家,但我不得不说第二种意见听起来更自然,对我来说更有意义。虽然我仍然需要弄清楚这是否属实,但为什么WPF会一直检测到这种变化,以便它继续检查CanExecute
答案 0 :(得分:10)
在您的CanExecuteDelegate
中,您已与CommandManager.RequerySuggested
挂钩。
因此,每当CommandManager.RequerySuggested被提出时,您的CanExecuteDelegate
都会被调用。
只要命令检测到对命令源的更改,就会引发CommandManager.RequerySuggested事件 管理器,范围从 Keyboard.KeyUpEvent , Mouse.ClickEvent 等。
此外,CommandManager有一个静态方法 - InvalidateRequerySuggested
,它强制CommandManager引发RequerySuggestedEvent。因此,您可以调用它来手动验证命令。
如果你想拿着控制来提升CanExecute,你可以使用PRISM提供的Delegate Command。仅当您明确调用Delegate Command公开的CanExecute
方法时,才会调用RaiseCanExecuteChanged()
委托。
合并评论以回答
从那以后每次转向VS时都会遇到断点 CommandManager RequerySuggested事件在失去焦点时被调用 窗口和窗口的激活属性已更改。这就是你的原因 请注意,当您移动到断点时,断点正在经常发生 VS因为焦点从WPF窗口移动到Visual Studio。
答案 1 :(得分:2)
当您设置命令时,运行时没有可靠的方法来了解您的CanExecute
将依赖哪些数据来做出决定。因此,当您拥有绑定到UI并在CommandManager
中注册的命令时,行为是,只要应用程序的状态发生更改,就会重新评估所有命令的CanExecute
。 WPF知道这一点的方式是更新绑定属性或发生UI事件时。
通常,只要绑定更新或发生某些控件事件,您就会看到调用CanExecute
(例如,当文本框的文本突出显示时,内置CanExecute
的{{1}}和{ {1}}命令会发生变化,因此突出显示事件会触发重新评估,我认为该重新评估会绑定到Cut
事件。
答案 2 :(得分:0)
可能由于未知原因UI可能会更新(测量,排列,然后渲染调用)。如果你设置了断点,可以执行方法,它将重新发生。换句话说,你无法通过这个断点,每次你做F5时,断点都会再次出现。
为了调查你应该把log / output语句放在你的can execute方法中,以及调用它的次数和时间。