更新标题:为什么 ICommand.CanExecute 一直被调用,而不是像事件一样工作? [英] Updated title: Why ICommand.CanExecute is getting called all the time, instead of working like an event?
问题描述
我在 WPF 中采用了 MVVM 模式并且已经学会了 Command
的使用.但是在我的实现中,我分配给实现 CanExecute
的委托总是被调用.我的意思是,如果我在委托函数中放置一个断点,则表明该函数不断被调用.根据我的理解(以及一种自然的思维方式,但当然我可能是错的),只有当我以某种方式通知状态更改时才会调用此委托,并且 CommandManager
(重新)检查CanExecute
属性并修改 UI 元素的 IsEnabled
属性.
I am adopting MVVM pattern in WPF and have learned the use of Command
. But in my implementation, the delegate I assigned to implement CanExecute
is always called. I mean if I put a break point inside the delegate function, it shows that this function keeps getting called. To my understanding (and a natural way of thinking, but of course I can be wrong), this delegate only gets called when I somehow notifies the change of the state and that's when the CommandManager
(re)checks the CanExecute
property and modify the IsEnabled
property of the UI element.
这是我的 VB.NET 实现,它最初来自 C# 版本.我确实注意到我需要对移植的代码进行一些更改才能编译.会不会是C#和VB.NET的底层不一样?那么有人可以为我提供一个原始的 VB.NET 实现,或者指出我有什么问题,或者如果我正确理解命令行为,该怎么办?
Here is my implementation of VB.NET, which I got originally from a C# version. I did notice that I needed to make some change to the ported code in order for it to compile. Could it be the underlying of C# and VB.NET is different? So can somebody provide me a original VB.NET implementation, or point me out what is wrong or do if I understand the Command behavior correctly?
这是我的 VB.NET 版本:
Here is my VB.NET version:
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
我如何实例化一个对象是这样的:
And how I instantiate an object is something like this:
MyCommand = New CommandBase(AddressOf CommandExec, AddressOf CanExecuteExec)
其中 CanExecuteExec 当然有这样的签名:
where the CanExecuteExec of course has the signature like this:
Private Function CanExecuteExec(obj As Object) As Boolean
就像我提到的,CanExecuteExec
一直在被调用.我想这是低效的,想象一下我有数百个 Command
对象,其中大部分 CanExecute
大部分时间都不会改变.
Like I mentioned, the CanExecuteExec
is getting called all the time. I guess it is inefficient, imagine that I have hundreds of Command
objects and most of the CanExecute
of them don't get changed most of the time.
有人说 CanExecute
确实一直被调用,而其他人则相反.我不是这方面的专家,但我不得不说第二种意见听起来更自然,对我来说更有意义.虽然我仍然需要弄清楚这是否属实,但为什么 WPF 一直检测更改以便它不断检查 CanExecute
Somebody says the CanExecute
indeed gets called all the time, while others say the opposite. I am no expert on this but I have to say the second opinion sounds more natural and makes more sense to me. Although I still need to figure out if that is true, why WPF detects the change all the time so that it keeps checking the CanExecute
推荐答案
在您的 CanExecuteDelegate
中,您可以连接到 CommandManager.RequerySuggested
.
In your CanExecuteDelegate
you have hook to CommandManager.RequerySuggested
.
因此,每当 CommandManager.RequerySuggested 引发您的 CanExecuteDelegate
将被调用.
So, whenever CommandManager.RequerySuggested is raised your CanExecuteDelegate
will be called.
CommandManager.RequerySuggested 事件在命令检测到命令源更改时引发管理器,范围从 Keyboard.KeyUpEvent、Mouse.ClickEvent 等
CommandManager.RequerySuggested event is raised whenever changes to the command source are detected by the command manager which ranges from Keyboard.KeyUpEvent, Mouse.ClickEvent etc.
此外,CommandManager 有一个静态方法 - InvalidateRequerySuggested
,它强制 CommandManager 引发 RequerySuggestedEvent.因此,您也可以调用它来手动验证您的命令.
Also, CommandManager has a static method - InvalidateRequerySuggested
which forces the CommandManager to raise the RequerySuggestedEvent. So, you can call that to validate your commands too manually.
如果您想掌握提高 CanExecute 的控制权,您可以使用 委托命令 由 PRISM 提供.CanExecute
委托仅在您显式调用由委托命令公开的 RaiseCanExecuteChanged()
方法时才会被调用.
If you want to take the control in hand for raising CanExecute, you can use the Delegate Command provided by PRISM. CanExecute
delegate will get called only when you explicitly call RaiseCanExecuteChanged()
method exposed by Delegate Command.
加入评论以回答
自从转向 VS 以来,每次都会遇到断点CommandManager RequerySuggested 事件在失去焦点时被调用窗口和激活属性更改的窗口.这就是为什么你请注意,当您移动到VS 因为焦点从 WPF 窗口移动到 Visual Studio.
Breakpoint is hitting every time on turning to VS since CommandManager RequerySuggested event gets called on lost focus of window and on activation property changed of window. That's why you notice that breakpoint is hitting every now and then when you move to VS since focus moves from WPF window to Visual Studio.
这篇关于更新标题:为什么 ICommand.CanExecute 一直被调用,而不是像事件一样工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!