4

私はMVVMパターンの基本レベルを試していますが、ICommand CanExecuteが変更されたことに気づきました。次のように XAML バインディングがあります。

    <ListBox ItemsSource="{Binding Contact.Addresses}"  x:Name="AddressCollections" Height="152" SelectedValue="{Binding SelectedAddress}"
             DockPanel.Dock="Top" />
    <Button Content="Add" Command="{Binding AddAddressCommand}" DockPanel.Dock="Top" />
    <Button Content="Remove" Command="{Binding DeleteAddressCommand}" DockPanel.Dock="Bottom" />

コマンド:

Public Class DeleteCommand
Implements ICommand

Private method As Object
Private methodname As String

Public Sub New(ByVal Controlname As String, ByVal mee As Object)
    methodname = Controlname
    method = mee
End Sub

Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
    Select Case methodname
        Case "Address"
            Return TryCast(method, ModelView.Contacts.ContactMV).CanDeleteAddress()
        Case "Numbers"
            Return TryCast(method, ModelView.Contacts.ContactMV).CanDeleteNumbers
        Case Else : Return False
    End Select
End Function

Public Event CanExecuteChanged(sender As Object, e As EventArgs) Implements ICommand.CanExecuteChanged

Public Sub Execute(parameter As Object) Implements ICommand.Execute
    Select Case methodname
        Case "Address"
            TryCast(method, ModelView.Contacts.ContactMV).DeleteAddress()
        Case "Numbers"
            TryCast(method, ModelView.Contacts.ContactMV).DeleteNumbers()
        Case Else

    End Select
End Sub
End Class

私のモデルビュー:

Public Class ContactMV

Property Contact As Model.Contacts.ContactMod
Property AddAddressCommand As New Commands.AddCommand("Address", Me)
Property DeleteAddressCommand As New Commands.DeleteCommand("Address", Me)
Property SelectedAddress As Model.Contacts.AddressModel
Public Sub AddAddress()
    If Contact.Addresses.Count = 0 Then
        Contact.Addresses.Add(New Model.Contacts.AddressModel(Contact.Primary.ID, True))
    Else
        Contact.Addresses.Add(New Model.Contacts.AddressModel(Contact.Primary.ID, False))
    End If

End Sub
Public Sub DeleteAddress()
    If IsNothing(SelectedAddress) = False Then
        Try
            Contact.Addresses.Remove(SelectedAddress)
        Catch ex As Exception
            MsgBox("Address not found")
        End Try
    End If
End Sub
Public Function CanDeleteAddress()
    If IsNothing(SelectedAddress) Then
        Return False
    Else
        Return Contact.Addresses.Contains(SelectedAddress)
    End If
End Function
End Class

問題は、 Canexecutechanged が開始時にのみ起動することです。実際には、リストボックス内の何かが選択されている場合にのみ削除ボタンを有効にしたいので、MVVM - ICommand バインディングメソッドで実行したいと考えています。どこが間違っていたのか、ICommand の実装を理解していなかったのかを説明してください。

ありがとうございました。

私が使用する更新されたRelay iCommandコード:

    Public Class RelayCommand
        Implements ICommand
        ''' <summary>
        ''' A command whose sole purpose is to relay its functionality to other objects by invoking delegates. The default return value for the CanExecute method is 'true'.
        ''' </summary>
        ''' <remarks></remarks>

#Region "Declarations"
        Private ReadOnly _CanExecute As Func(Of Boolean)
        Private ReadOnly _Execute As Action
#End Region

#Region "Constructors"
        Public Sub New(ByVal execute As Action)
            Me.New(execute, Nothing)
        End Sub

        Public Sub New(ByVal execute As Action, ByVal canExecute As Func(Of Boolean))
            If execute Is Nothing Then
                Throw New ArgumentNullException("execute")
            End If
            _Execute = execute
            _CanExecute = canExecute
        End Sub
#End Region

#Region "ICommand"
        Public Custom Event CanExecuteChanged As EventHandler Implements System.Windows.Input.ICommand.CanExecuteChanged

            AddHandler(ByVal value As EventHandler)
                If _CanExecute IsNot Nothing Then
                    AddHandler CommandManager.RequerySuggested, value
                End If
            End AddHandler
            RemoveHandler(ByVal value As EventHandler)

                If _CanExecute IsNot Nothing Then
                    RemoveHandler CommandManager.RequerySuggested, value
                End If
            End RemoveHandler

            RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
                'This is the RaiseEvent block
                'CommandManager.InvalidateRequerySuggested()
            End RaiseEvent
        End Event

        Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
            If _CanExecute Is Nothing Then
                Return True
            Else
                Return _CanExecute.Invoke
            End If
        End Function

        Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
            _Execute.Invoke()
        End Sub
#End Region
    End Class

ほとんどのコードはコピーですが、以下のコメントで動作を理解しました。

4

2 に答える 2

7

Raul Otaño が指摘したように、CanExecuteChanged. ただし、すべての MVVM フレームワークがRaiseCanExecuteChangedメソッドを提供するわけではありません。CanExecuteChangedまた、実際のイベントは UI スレッドで呼び出す必要があることにも注意してください。したがって、モデル内のスレッドからのコールバックが必要な場合は、次のように UI スレッドにコールバックする必要があります。

    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
        {
            Application.Current.Dispatcher.Invoke((Action)(() => { CanExecuteChanged(this, EventArgs.Empty); }));
        }
    }

CommandManager.InvalidateRequerySuggested()これは機能的には機能し、小さなアプリケーションでは問題ありませんが、無差別であり、すべてのコマンドを再クエリする可能性があるため、呼び出すことはお勧めしません! 多くのコマンドを含む大規模なシステムでは、これは非常に遅くなる可能性があります!

于 2013-10-30T13:59:56.400 に答える
5

RaiseCanExecuteChangedICommand の実装には、イベントを発生させるようなメソッドが必要CanExecuteChangedです。次に、リスト内の選択されたアイテムが変更されるたびに、ビューモデルで必要なRaiseCanExecuteChangedコマンドから実行します。GalaSoft RelayCommandMVVMLite ライブラリの やDelegateCommand. お役に立てれば...

于 2013-10-29T12:41:55.080 に答える