سؤال

Goal

I want the button btnRefresh to be enabled when the Textbox tbMachineNo has something in it (using the MVVM standards).


Project Summary

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

Problem

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.

هل كانت مفيدة؟

المحلول 2

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!

نصائح أخرى

  1. Make sure that your UpdateSourceTrigger is set to PropertyChanged
  2. In your property setter, call RefreshMachineNo.RaiseCanExecuteChanged()

RaiseCanExecuteChanged is a standard method found on DelegateCommand and RelayCommand. Hopefully you're using one of the industry standard ICommand implementations for your commands.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top