Relay Command doesn't get triggered.

Eduardo Gomez Romero 185 Reputation points
2024-03-26T01:16:51.1033333+00:00

I am making a ribbon like menu.

For achieving, I created three basic components.

  • Component Item Class
  • Menu Template (XAML)
  • Menu Template (Code Behind)

The class define each item


public class MenuComponentItems {

    public string ImageSource { get; set; }

    public string CommandParameter { get; set; }

    public string Section { get; set; }

    public IRelayCommand Command { get; set; }

}

then we will define the UI


<Border

    Margin="5,5,0,0"

    HeightRequest="120"

    VerticalOptions="StartAndExpand">

    <Grid

        RowSpacing="5"

        VerticalOptions="Center">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto" />

            <RowDefinition Height="Auto" />

        </Grid.RowDefinitions>

        <HorizontalStackLayout

            x:Name="MenuItemsStack"

            BackgroundColor="Bisque" />

        <Label

            Grid.Row="1"

            HorizontalTextAlignment="Center"

            Text="{Binding SectionName, Source={x:Reference MenuComponent}}" />

    </Grid>

</Border>

and finally, the code behind of the control


public partial class MenuTemplate : ContentView {

public ObservableCollection<MenuComponentItems> MenuItems { get; set; } = [];

public MenuTemplate() {

        InitializeComponent();

        MenuItems.CollectionChanged += (sender, e) => UpdateMenu();

}

public static readonly BindableProperty SectionNameProperty = BindableProperty.Create(

    nameof(SectionName),

    typeof(string),

    typeof(MenuTemplate));

public string SectionName {

    get => (string)GetValue(SectionNameProperty);

    set => SetValue(SectionNameProperty, value);

}

private void UpdateMenu() {

    MenuItemsStack.Children.Clear();

    foreach (var menuItem in MenuItems) {

        var imageButton = new ImageButton {

            Source = menuItem.ImageSource,

            WidthRequest = 60,

            HeightRequest = 60,

            Margin = new Thickness(10, 0, 10, 0),

            Command = menuItem.Command,

            CommandParameter = menuItem.CommandParameter

        };

        MenuItemsStack.Children.Add(imageButton);

    }

}

usage


<Grid RowDefinitions="200, *">

    <HorizontalStackLayout>

        <controls:MenuTemplate SectionName="ferwqfkrew">

            <controls:MenuTemplate.MenuItems>

                <models:MenuComponentItems

                    ImageSource="dotnet_bot.png"

                    Section="Section 1" />

                <models:MenuComponentItems

                    ImageSource="mario.png"

                    Section="Section 1" />

            </controls:MenuTemplate.MenuItems>

        </controls:MenuTemplate>

    </HorizontalStackLayout>

</Grid>

output

output

Problem

when I create a relay command in my view model

  [RelayCommand]

  public void MenuItemSelected(object param) {



      Debug.WriteLine("dcd");

  }

and bind it I get

property, BindableProperty, or event found for "Command", or mismatching.

What I do not, is the fact that in my class I have a RelayCommand and my vm is a RelayCommand as well.

At first, I thought that is because a ImageButton command is an ICommand and not a RelayCommand, but I tested an ImageButton with the same command and it triggered

Thing that I tried

  1. Using ICommand instead of the RelayCommand of the Microsoft mvvm toolkit
  2. Created a RelayCommand property in the control itself

Update

I made my class inherit form ContentView


public class MenuComponentItems : ContentView {

    public string ImageSource { get; set; }

    public string CommandParameter { get; set; }

    public static readonly BindableProperty CommandProperty = BindableProperty.Create(

        nameof(Command), typeof(RelayCommand), typeof(MenuComponentItems));

    public RelayCommand Command {

        get => (RelayCommand)GetValue(CommandProperty);

        set => SetValue(CommandProperty, value);

    }

}

but it doesn't trigger the command.

Usage

public class MenuComponentItems : ContentView {

public string ImageSource { get; set; }

public string CommandParameter { get; set; }

public static readonly BindableProperty CommandProperty = BindableProperty.Create(

    nameof(Command), typeof(RelayCommand), typeof(MenuTemplate));

public RelayCommand Command {

    get => (RelayCommand)GetValue(CommandProperty);

    set => SetValue(CommandProperty, value);

}

  <controls:MenuTemplate SectionName="ferwqfkrew">

      <controls:MenuTemplate.MenuItems>

          <models:MenuComponentItems Command="{Binding MenuItemSelectedCommand}"

              ImageSource="dotnet_bot.png" />

public partial class MainViewModel : ObservableObject {





    [RelayCommand]

    public void MenuItemSelected() {



        Debug.WriteLine("dcd");

    }

}

I inspected the MenuItemsStack.Children.Add(imageButton); and for some reason the command is null.

I tested it with a button, and it works, so the VM is fine, the problem is the custom control that doesn't get the command

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
2,837 questions
{count} votes

Accepted answer
  1. Leon Lu (Shanghai Wicresoft Co,.Ltd.) 67,781 Reputation points Microsoft Vendor
    2024-03-28T03:58:05.52+00:00

    Hello,

    You can add command to the ImageButton in the UpdateMenu method by C# code. And remove Command = menuItem.Command, and CommandParameter = menuItem.CommandParameter

    private void UpdateMenu()
       {
    
    
          MenuItemsStack.Children.Clear();
    
    
          foreach (var menuItem in MenuItems)
           {
    
    
              var imageButton = new ImageButton
               {
    
    
                  Source = menuItem.ImageSource,
    
    
                  WidthRequest = 60,
    
    
                  HeightRequest = 60,
    
    
                  Margin = new Thickness(10, 0, 10, 0),
    
    
                 // Command = menuItem.Command,
    
    
                 // CommandParameter = menuItem.CommandParameter
    
    
              };
    
    //add it like here.
           imageButton.SetBinding(ImageButton.CommandProperty, new Binding("MenuItemSelectedCommand"));
    
    
          Binding objBinding1 = new Binding()
           {
               Source = imageButton
           };
           imageButton.SetBinding(ImageButton.CommandParameterProperty, objBinding1);
    
    
          MenuItemsStack.Children.Add(imageButton);
    
    
          }
    
    
      }
    

    Then if you want to know which image button was clicked, you need to binding CommandParameterProperty.

    And you need to add attribute in the MenuItemSelected method like following code.

      public partial class MainViewModel : ObservableObject
    
      {
    
          [RelayCommand]
    
          public void MenuItemSelected(object c)
    
          {
    
              var res = c;
    
              Debug.WriteLine("==========dcd");
    
          }
    
      }
    

    Best Regards,

    Leon Lu


    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.


0 additional answers

Sort by: Most helpful