Imagine, you have a simple WPF window with just a TextBox
and a Button
on it. The TextBox
's Text
property is bound to a property called FileName
and the Button
's Command
property is bound to a property called ImportCommand
.
<StackPanel>
<TextBox Text="{Binding FileName, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="Import" Command="{Binding ImportCommand}" />
</StackPanel>
The view model is pretty much boiler plate code as well.
Public Class MainViewModel
Inherits ObservableItem
Private _fileName As String
Private _importCommand As ICommand = New RelayCommand(AddressOf Me.Import, AddressOf Me.CanImport)
Public Sub New()
Me.FileName = "C:\Temp\temp.dat"
End Sub
Public Property FileName As String
Get
Return _fileName
End Get
Set(value As String)
MyBase.SetProperty(Of String)(_fileName, value)
End Set
End Property
Public ReadOnly Property ImportCommand As ICommand
Get
Return _importCommand
End Get
End Property
Private Sub Import()
Throw New NotImplementedException
End Sub
Private Function CanImport() As Boolean
Return Not String.IsNullOrEmpty(Me.FileName) AndAlso IO.File.Exists(Me.FileName)
End Function
End Class
There's no obvious connection between the TextBox
and the Button
, and there's no obvious connection between the FileName
property and the ImportCommand
.
So, how does the ImportCommand
detect, that I may have changed the FileName
property and that this change may affect the enabled state of the Button
, the ImportCommand
is bound to?
Does WPF call CanExecute
on any Command
and any PropertyChanged
that's happening? Sounds like a lot of unnecessary work to me?
The CanExecuteChanged event from the RelayCommad listens to the CommandManager.RequerySuggested event that is raised by the CommandManager.InvalidateRequerySuggested method.
The CommandManager again listens to the InputManager KeyUp MouseUp or GotKeyboardFocus or LostKeyboardFocus events and calls InvalidateRequerySuggested to notify the UI to call the CanExecute method of the Command.