Título actualizado: ¿Por qué se llama a ICommand.CanExecute todo el tiempo, en lugar de funcionar como un evento?
Estoy adoptando el patrón MVVM en WPF y he aprendido el uso deCommand
. Pero en mi implementación, el delegado que asigné para implementarCanExecute
Siempre se llama. Quiero decir que si pongo un punto de interrupción dentro de la función de delegado, muestra que esta función sigue siendo llamada. A mi entender (y una forma natural de pensar, pero por supuesto que puedo estar equivocado), este delegado solo es llamado cuando de alguna manera notifico el cambio de estado y ahí es cuandoCommandManager
(re) comprueba elCanExecute
propiedad y modificar elIsEnabled
Propiedad del elemento UI.
Aquí está mi implementación de VB.NET, que obtuve originalmente de una versión de C #. Noté que necesitaba hacer algún cambio en el código portado para que se compile. ¿Podría ser el subyacente de C # y VB.NET es diferente? Entonces, ¿alguien puede proporcionarme una implementación VB.NET original, o señalarme qué es lo que está mal o hacer si entiendo correctamente el comportamiento del Comando?
Aquí está mi versión de VB.NET:
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
Y cómo instanciar un objeto es algo como esto:
MyCommand = New CommandBase(AddressOf CommandExec, AddressOf CanExecuteExec)
donde CanExecuteExec, por supuesto, tiene la firma como esta:
Private Function CanExecuteExec(obj As Object) As Boolean
Como he mencionado, elCanExecuteExec
es llamado todo el tiempo. Supongo que es ineficiente, imagina que tengo cientos deCommand
objetos y la mayoría de losCanExecute
De ellos no se cambian la mayor parte del tiempo.
Alguien diceCanExecute
De hecho, es llamado todo el tiempo, mientras que otros dicen lo contrario. No soy un experto en esto, pero debo decir que la segunda opinión suena más natural y tiene más sentido para mí. Aunque todavía tengo que averiguar si eso es cierto, ¿por qué WPF detecta el cambio todo el tiempo para que siga revisando elCanExecute