首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ICommand CanExecuteChanged没有更新

ICommand CanExecuteChanged没有更新
EN

Stack Overflow用户
提问于 2013-10-29 11:51:51
回答 2查看 6.8K关注 0票数 4

我正在尝试MVVM模式的基本水平,并在ICommand CanExecute上被打动了。我的XAML绑定如下:

代码语言:javascript
复制
    <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" />

命令:

代码语言:javascript
复制
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

我的ModelView:

代码语言:javascript
复制
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只在启动时才会启动,实际上,只有在选中列表框中的某个内容时才启用delete按钮,而且我希望通过MVVM - ICommand绑定方法完成该操作。请您解释一下我哪里出错了,或者错过了理解ICommand实现的地方。

谢谢。

我使用的更新的中继iCommand代码:

代码语言:javascript
复制
    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

大部分代码都是副本,但我理解了下面的注释。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-10-29 12:41:55

您的ICommand实现中必须有一些方法,如RaiseCanExecuteChanged,可以触发事件CanExecuteChanged。然后,每当列表中的选定项发生更改时,在视图模型中都会根据所需的命令执行RaiseCanExecuteChanged。我建议您使用任何泛型命令,如RelayCommand of GalaSoft MVVMLite库或DelegateCommand的任何实现。希望这能帮上忙。

票数 5
EN

Stack Overflow用户

发布于 2013-10-30 13:59:56

正如劳尔·奥塔尼奥( Raul Ota O)指出的,你可以提高CanExecuteChanged。然而,并不是所有的MVVM框架都提供RaiseCanExecuteChanged方法。还值得注意的是,必须在UI线程上调用实际事件CanExecuteChanged。因此,如果您期望从模型中的某个线程得到回调,则需要将其调用回UI线程,如下所示:

代码语言:javascript
复制
    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
        {
            Application.Current.Dispatcher.Invoke((Action)(() => { CanExecuteChanged(this, EventArgs.Empty); }));
        }
    }

我非常建议不要调用CommandManager.InvalidateRequerySuggested(),因为虽然这在功能上是可行的,对于小型应用程序也可以,但它是不分青红皂白的,可能会重新查询每个命令!在一个拥有大量命令的大型系统中,这可能非常慢!

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19657463

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档