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
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
- Using ICommand instead of the RelayCommand of the Microsoft mvvm toolkit
- 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