Título atualizado: Por que o ICommand.CanExecute está sendo chamado o tempo todo, em vez de funcionar como um evento?
Eu estou adotando o padrão MVVM no WPF e aprendi o uso deCommand
. Mas na minha implementação, o delegado que designei para implementarCanExecute
é sempre chamado. Quer dizer, se eu colocar um ponto de interrupção dentro da função delegada, isso mostra que essa função está sendo chamada. Para meu entendimento (e um modo natural de pensar, mas é claro que posso estar errado), este delegado só é chamado quando eu de alguma forma notifico a mudança do estado e é aí que oCommandManager
(re) verifica oCanExecute
propriedade e modificar oIsEnabled
propriedade do elemento da interface do usuário.
Aqui está a minha implementação do VB.NET, que obtive originalmente de uma versão em C #. Eu notei que precisava fazer alguma alteração no código portado para que ele compilasse. Poderia ser o subjacente do C # e VB.NET é diferente? Então, alguém pode me fornecer uma implementação original do VB.NET ou me apontar o que está errado ou fazer se eu entendi o comportamento do Comando corretamente?
Aqui está a minha versão do 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
E como eu instancio um objeto é algo assim:
MyCommand = New CommandBase(AddressOf CommandExec, AddressOf CanExecuteExec)
onde o CanExecuteExec, claro, tem a assinatura assim:
Private Function CanExecuteExec(obj As Object) As Boolean
Como eu mencionei, oCanExecuteExec
está sendo chamado o tempo todo. Eu acho que é ineficiente, imagine que eu tenho centenas deCommand
objetos e mais doCanExecute
deles não são alterados a maior parte do tempo.
Alguém diz que oCanExecute
de fato é chamado o tempo todo, enquanto outros dizem o contrário. Não sou especialista nisso, mas devo dizer que a segunda opinião soa mais natural e faz mais sentido para mim. Embora eu ainda precise descobrir se isso é verdade, por que o WPF detecta a alteração o tempo todo para que ele continue verificando oCanExecute