How to Avoid a RelayCommand Error

RogerSchlueter-7899 1,256 Reputation points
2024-02-11T23:35:24.8333333+00:00

In a ViewModel for a wpf window I have the following command:

Private ReadOnly Property _AddVehicle As New RelayCommand(AddressOf OnAddVehicle())
Public ReadOnly Property AddVehicle As RelayCommand
	Get
		Return _AddVehicle
	End Get
End Property

I am using the nomional version of RelayCommand. Because I have Option Strict On, I get the following error:

Option Strict On does not allow narrowing in implicit type conversions between method 'Private Sub OnAddVehicle()' and delegate 'Delegate Sub Action(Of Object)(obj As Object)'.

I know I can fix this by using this for the argument to RelayCommand:

... RelayCommand(Sub() OnAddVehicle())

However, there are other factors that are easily met by using the "AddressOf" argument. So my questions are: Why am I getting the error? Is there a way to use the "AddressOf" argument to RelayCommand?

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,708 questions
VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,653 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Hui Liu-MSFT 47,256 Reputation points Microsoft Vendor
    2024-02-12T03:12:59.4733333+00:00

    Hi,@ RogerSchlueter-7899. Welcome to Microsoft Q&A. The issue you're facing with the RelayCommand and AddressOf is related to the fact that AddressOf in VB.NET includes parentheses when used with a method, turning it into a delegate invocation. This can cause a type mismatch in cases where the delegate's signature doesn't match the method's signature. In your case, the RelayCommand expects a delegate with the signature Action(Of Object), but when you use AddressOf OnAddVehicle(), you are essentially trying to create a delegate with the signature Action(Of Object) that invokes the result of OnAddVehicle().

    Private ReadOnly Property _AddVehicle As New RelayCommand(AddressOf OnAddVehicle)
    Public ReadOnly Property AddVehicle As RelayCommand
        Get
            Return _AddVehicle
        End Get
    End Property
    Private Sub OnAddVehicle()
        ' Your implementation here
    End Sub
    

    By removing the parentheses after OnAddVehicle, you're passing the method itself as a delegate to the RelayCommand constructor, rather than trying to invoke it immediately. Alternatively, as you've mentioned, you could also use a lambda expression to achieve the same result:

    Private ReadOnly Property _AddVehicle As New RelayCommand(Sub() OnAddVehicle())
    Public ReadOnly Property AddVehicle As RelayCommand
        Get
            Return _AddVehicle
        End Get
    End Property
    Private Sub OnAddVehicle()
        ' Your implementation here
    End Sub
    
    

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Peter Fleischer (former MVP) 19,311 Reputation points
    2024-02-12T05:05:07.22+00:00

    Hi Roger,
    you must check constructors in RelayCommand class. RelayCommand class can look like this:

    Public Class RelayCommand
      Implements ICommand
    #Region "Fields"
      ' delegate to execute
      Private ReadOnly _execute As Action(Of Object)
      Private ReadOnly _canExecute As Predicate(Of Object)
    #End Region ' Fields
    #Region "Constructors"
      ''' <summary>
      ''' in ctor get delegate to execute
      ''' </summary>
      ''' <param name="execute">The execution logic.</param>
      Public Sub New(ByVal execute As Action(Of Object))
        Me.New(execute, Nothing)
      End Sub
    ...
    

    Parameter in AddressOf must be only the name of method (without parantheses)

    	Private ReadOnly Property _AddVehicle As New RelayCommand(AddressOf OnAddVehicle)
    	Public ReadOnly Property AddVehicle As RelayCommand
    		Get
    			Return _AddVehicle
    		End Get
    	End Property
    
    	''' <summary>
    	''' There's no constructor in RelayCommand class with this signature and method is not necessary
    	''' </summary>
    	Private Sub OnAddVehicle()
    		''
    	End Sub
    
    	''' <summary>
    	''' This method work for RelayCommand class
    	''' </summary>
    	''' <param name="par"></param>
    	Private Sub OnAddVehicle(par As Object)
    		''
    	End Sub