Search code examples
wpfvb.netmvvm.net-4.5stack-overflow

StackOverflowExcpetion When Executing Command


I have created a Class which Inherits ICommand

Public Class RelayCommand(Of T)
    Implements ICommand
    Private ReadOnly m_oExecute As Action(Of T)
    Private ReadOnly m_fCanExecute As Predicate(Of T)


Public Sub New(execute As Action(Of T))
    Me.New(execute, Nothing)
End Sub

Public Sub New(execute As Action(Of T), canExecute As Predicate(Of T))
    If execute Is Nothing Then
        Throw New ArgumentNullException("execute")
    End If

    Me.m_oExecute = execute
    Me.m_fCanExecute = canExecute
End Sub

Public Function CanExecute(parameter As T) As Boolean
    Return IIf(Me.m_fCanExecute Is Nothing, True, Me.CanExecute(parameter))
End Function

Public Sub Execute(parameter As T)
    Me.execute(parameter)
End Sub


Private Function ICommand_CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
    Return Me.CanExecute(CType(parameter, T))
End Function

Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
    AddHandler(value As EventHandler)
        AddHandler CommandManager.RequerySuggested, value
    End AddHandler

    RemoveHandler(value As EventHandler)
        RemoveHandler CommandManager.RequerySuggested, value
    End RemoveHandler

    RaiseEvent(sender As Object, e As EventArgs)

    End RaiseEvent
End Event


    Private Sub ICommand_Execute(parameter As Object) Implements ICommand.Execute
        Me.Execute(CType(parameter, T))
    End Sub

End Class

Public Class RelayCommand
    Inherits RelayCommand(Of Object)
    Public Sub New(execute As Action(Of Object))
        MyBase.New(execute)
    End Sub

    Public Sub New(execute As Action(Of Object), canExecute As Predicate(Of Object))
        MyBase.New(execute, canExecute)
    End Sub
End Class

In the .xaml file I have wrote this code:

<ComboBox x:Name="cboDatabases" Width="150">
    <i:Interaction.Triggers>
         <i:EventTrigger EventName="DropDownOpened">
             <i:InvokeCommandAction Command="{Binding                        DataContext.DropDownOpenedCommand,ElementName=cboDatabases}" />
         </i:EventTrigger>
    </i:Interaction.Triggers>
</ComboBox>

And the Command Object in ViewModel

Private m_oDropDownOpenedCommand As RelayCommand
Public ReadOnly Property DropDownOpenedCommand As ICommand
    Get
        If IsNothing(m_oDropDownOpenedCommand) Then
            Me.m_oDropDownOpenedCommand = New RelayCommand(AddressOf Me.DropDownOpened, Function(param) True)
        End If
        Return Me.m_oDropDownOpenedCommand
    End Get
End Property

Private Sub DropDownOpened()
    MessageBox.Show("i did it")
End Sub

When I create a new Instance of the Window the code inserts the Property DropDownOpenedCommand as expected. When I click the combo so as to trigger the event then the code calls many times this Function in the RelayCommand Class

Public Function CanExecute(parameter As T) As Boolean
        Return IIf(Me.m_fCanExecute Is Nothing, True, Me.CanExecute(parameter))
    End Function

As a result I get a StackOverflowException at that Line. The CanExecute Returns false after the first time that it gets to that line. BUT The parameter field is always nothing. I think that the parameter being nothing is a problem but I can't figure how to pass the right argument. Any Ideas?? I know that I can handle the event in the xaml.vb but I want it as a Command in the Viewmodel.


Solution

  • Public Function CanExecute(parameter As T) As Boolean
        Return IIf(Me.m_fCanExecute Is Nothing, True, Me.CanExecute(parameter))
    End Function
    

    If Me.m_fCanExecute is ever not null, the function recurses on itself by evaluating Me.CanExecute() again. That's where the stackoverflowexception is being generated.

    edit:

    So the first time you come into this method and Me.m_fCanExecute is not null, it again executes Me.CanExecute(parameter), then Me.m_fCanExecute is null again, so it calls Me.CanExecute(), then Me.m_fCanExecute is null again, so it calls Me.CanExecute(), then Me.m_fCanExecute is null again, so it calls Me.CanExecute(), then Me.m_fCanExecute is null again, so it calls Me.CanExecute(), then Me.m_fCanExecute is null again, so it calls Me.CanExecute() ...

    and then you get a StackOverFlowException. It's an infinite loop.