Zaktualizowany tytuł: Dlaczego ICommand.CanExecute jest wywoływany przez cały czas, zamiast pracować jak wydarzenie?
Przyjmuję wzór MVVM w WPF i nauczyłem się korzystać zCommand
. Ale w mojej realizacji delegat, którego wyznaczyłem do wdrożeniaCanExecute
jest zawsze nazywany. To znaczy, jeśli umieściłem punkt przerwania wewnątrz funkcji delegata, to pokazuje, że ta funkcja nadal jest wywoływana. Dla mojego zrozumienia (i naturalny sposób myślenia, ale oczywiście mogę się mylić), ten delegat zostaje wezwany tylko wtedy, gdy jakoś powiadamiam o zmianie stanu i wtedyCommandManager
(re) sprawdzaCanExecute
własność i zmodyfikujIsEnabled
właściwość elementu interfejsu użytkownika.
Oto moja implementacja VB.NET, którą otrzymałem pierwotnie z wersji C #. Zauważyłem, że muszę dokonać pewnych zmian w przeniesionym kodzie, aby mógł się skompilować. Czy może to być podstawa C # i VB.NET jest inny? Czy ktoś może mi udostępnić oryginalną implementację VB.NET lub wskazać, co jest nie tak lub co zrobić, jeśli poprawnie rozumiem zachowanie polecenia?
Oto moja wersja 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
A jak tworzę instancję obiektu, to coś takiego:
MyCommand = New CommandBase(AddressOf CommandExec, AddressOf CanExecuteExec)
gdzie CanExecuteExec ma oczywiście taki podpis:
Private Function CanExecuteExec(obj As Object) As Boolean
Jak wspomniałem,CanExecuteExec
ciągle się nazywa. Sądzę, że to nieefektywne, wyobraź sobie, że mam setkiCommand
przedmioty i większośćCanExecute
z nich nie zmienia się przez większość czasu.
Ktoś mówiCanExecute
rzeczywiście jest wywoływany przez cały czas, podczas gdy inni mówią przeciwnie. Nie jestem ekspertem w tej dziedzinie, ale muszę powiedzieć, że druga opinia brzmi bardziej naturalnie i ma dla mnie więcej sensu. Chociaż nadal muszę się dowiedzieć, czy to prawda, dlaczego WPF cały czas wykrywa zmianę, aby nadal sprawdzaćCanExecute