Я принимаю шаблон MVVM в WPF и узнал об использовании Command
. Но в моей реализации всегда вызывается делегат, назначенный мне для реализации CanExecute
. Я имею в виду, если бы я поставил точку останова внутри функции делегата, это показывает, что эта функция продолжает получать вызовы. К моему пониманию (и естественному мышлению, но, конечно, я могу ошибаться), этот делегат вызван только тогда, когда я как-то уведомляю об изменении состояния, и тогда CommandManager
(re) проверяет свойство CanExecute
и модифицирует IsEnabled
свойство элемента интерфейса.Обновлено название: Почему ICommand.CanExecute получает вызов все время, вместо того, чтобы работать как событие?
Вот моя реализация VB.NET, которую я получил из версии C#. Я заметил, что мне нужно внести некоторые изменения в портированный код, чтобы он мог компилироваться. Может ли быть основой C# и VB.NET отличается? Так может ли кто-нибудь предоставить мне оригинальную реализацию VB.NET или указать мне, что не так, или если я правильно понимаю поведение команды?
Вот моя версия 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
И как я создаю экземпляр объекта что-то вроде этого:
MyCommand = New CommandBase(AddressOf CommandExec, AddressOf CanExecuteExec)
где CanExecuteExec, конечно, имеет подпись, как это:
Private Function CanExecuteExec(obj As Object) As Boolean
Как я уже упоминал, CanExecuteExec
все время звонит. Я думаю, что это неэффективно, представьте, что у меня есть сотни Command
объектов, и большинство из них CanExecute
не меняются большую часть времени.
UPDATE:
Кто-то говорит, что CanExecute
действительно вызывается все время, в то время как другие говорят об обратном. Я не эксперт в этом, но я должен сказать, что второе мнение звучит более естественно и имеет больше смысла для меня. Хотя мне все еще нужно выяснить, верно ли это, почему WPF постоянно обнаруживает изменение, так что он продолжает проверять CanExecute
Что вы хотите сказать? 'CanExecute' * does * вызывается все время - ваше понимание не совсем корректно, но вы на самом деле не задали вопрос здесь. –
@DanPuzey прав, вы не понимаете правильно, делегаты can-execute всегда вызываются. –
@tete: вы разместили свое обновление, но мой вопрос: когда вы думаете, что ваша команда 'CanExecute' должна« естественно »быть вызвана? Как вы это делаете логично - помните, что кто-то должен писать код, который будет функционировать для всех сценариев, для всех приложений, для всех команд, для всех возможных источников данных и сложности интерфейса? Не зная содержимого метода CanExecute, единственным вариантом является запрос * много *. –