I want the button btnRefresh
to be enabled when the Textbox tbMachineNo
has something in it (using the MVVM standards).
I have a:
Window.xaml
<TextBox Text="{Binding Inspection.Machine.MachineNumber, UpdateSourceTrigger=PropertyChanged}" />
<Button Command="{Binding RefreshMachineNo}" />
InspectionViewModel.vb
This has a property of InspectionModel
and contains several methods. One being that my ICommand gets executed during my constructor (and that's what disables / enables my textbox because of the CanUpdate
method)
Public Class InspectionViewModel
Private _Inspection As InspectionModel
Private _RefreshMachineNo As ICommand
Public Property Inspection As InspectionModel
Get
Return _Inspection
End Get
Set(value As InspectionModel)
_Inspection = value
End Set
End Property
Public Sub New()
_Inspection = New InspectionModel("Version", "Title of machine", "Model", "Owner", "Department", Date.Now, New MachineModel)
RefreshMachineNo = New RefreshMachineNumberCommand(Me) 'Calls the CanUpdate, and if it returns true, it executes FetchMachineDetails()
End Sub
Public Property RefreshMachineNo As ICommand
Get
Return _RefreshMachineNo
End Get
Set(value As ICommand)
_RefreshMachineNo = value
End Set
End Property
Public ReadOnly Property CanUpdate As Boolean
Get
If Inspection Is Nothing Then
Return False
End If
Return Not String.IsNullOrWhiteSpace(Inspection.Machine.MachineNumber)
End Get
End Property
Public Sub FetchMachineDetails()
Dim MachineNo As String = Inspection.Machine.MachineNumber
End Sub
End Class
This works fine, the code is executed when it should. Now take a look at my InpsectionModel.
RefreshMachineNumberCommand
Public Class RefreshMachineNumberCommand
Implements ICommand
Private _viewModel As InspectionViewModel
Public Sub New(ByVal viewModel As InspectionViewModel)
_viewModel = viewModel
End Sub
Public Event CanExecuteChanged(sender As Object, e As System.EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged
Public Function CanExecute(parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
Return _viewModel.CanUpdate()
End Function
Public Sub Execute(parameter As Object) Implements System.Windows.Input.ICommand.Execute
_viewModel.FetchMachineDetails()
End Sub
End Class
InspectionModel.vb
This class inherits my ObservableObject which is what implements the INotifyPropertyChanged
. So in theory, whenever my property MachineNumber
changes in the Inspection object Machine
, it should trigger the UpdateSourceTrigger=PropertyChanged
Public Class InspectionModel
Inherits ObservableObject
Private _Version As String
Private _Title As String
Private _Model As String
Private _InspectionOwner As String
Private _Department As String
Private _DateEntry As Date
Private _Machine As MachineModel
Public Property Version As String
Get
Return _Version
End Get
Set(value As String)
_Version = value
Notify("Version")
End Set
End Property
Public Property Title As String
Get
Return _Title
End Get
Set(value As String)
_Title = value
Notify("Title")
End Set
End Property
Public Property Model As String
Get
Return _Model
End Get
Set(value As String)
_Model = value
Notify("Model")
End Set
End Property
Public Property InspectionOwner As String
Get
Return _InspectionOwner
End Get
Set(value As String)
_InspectionOwner = value
Notify("InspectionOwner")
End Set
End Property
Public Property Department As String
Get
Return _Department
End Get
Set(value As String)
_Department = value
Notify("Department")
End Set
End Property
Public Property DateEntry As Date
Get
Return _DateEntry
End Get
Set(value As Date)
_DateEntry = value
Notify("DateEntry")
End Set
End Property
Public Property Machine As MachineModel
Get
Return _Machine
End Get
Set(value As MachineModel)
_Machine = value
Notify("Machine")
End Set
End Property
Public Sub New(ByVal Version As String, ByVal Title As String, ByVal Model As String, ByVal InspectionOwner As String, ByVal Department As String, ByVal DateEntry As Date, ByVal Machine As MachineModel)
Me.Version = Version
Me.Title = Title
Me.Model = Model
Me.InspectionOwner = InspectionOwner
Me.Department = Department
Me.DateEntry = DateEntry
Me.Machine = Machine
End Sub
End Class
I am not grasping how to enable / disable my button control when the textbox becomes populated with characters or when it is empty. The CanUpdate
of my ICommand is what currently controls this and only gets executed once when the constructor is loaded.
This makes sense, but I am not sure how to make this Textchanged issue work without putting code behind. I want to be able to do it using MVVM
I bound my Textbox to another field and that field was bounded to the same attribute in the Inspection object. I could see the other field getting modified as I typed in the textbox ... So the UpdateSourceTrigger is working but I can't get the button to enable when I type text.
My problem rested in my RefreshMachineNumberCommand.vb
class.
More specifically, my CanExecuteChanged event did not handle the CommandManager. Here's what I did to fix it:
Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
AddHandler(ByVal value As EventHandler)
AddHandler CommandManager.RequerySuggested, value
End AddHandler
RemoveHandler(ByVal value As EventHandler)
RemoveHandler CommandManager.RequerySuggested, value
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
CanExecute(sender)
End RaiseEvent
End Event
For more information, this post helped me a lot!