0

I don't know how I can pass a single property via CommandParameter to my Command function in the ViewModel.

Now I pass the whole object (CategoryListItem) but I only need the value from the Id property. How can I achieve this?

Class:

public class CategoryListItem
{
    public int Id { get; set; }
    public int Order { get; set; }

    public string Name { get; set; }
}

ViewModel:

public ObservableRangeCollection<CategoryListItem> Listing
    {
        get => _listing;
        set => SetProperty(ref _listing, value);
    }

OnItemTappedCommand = new DelegateCommand<CategoryListItem>(OnItemTapped);

private async void OnItemTapped(CategoryListItem obj)
    {
        await _navigationService.GoBackAsync(new NavigationParameters
        {
            { "CategoryId", obj.Id }
        });
    }

XAML:

<ListView
        ItemsSource="{ Binding Listing }"
        HasUnevenRows="false"
        CachingStrategy="RecycleElement"
        SeparatorColor="{ DynamicResource AccentColor }">

        <ListView.Behaviors>
            <b:EventToCommandBehavior 
                EventName="ItemTapped"
                Command="{ Binding OnItemTappedCommand }"
                CommandParameter="???"
                EventArgsConverter="{ StaticResource ItemTappedEventArgsConverter }">
            </b:EventToCommandBehavior>
        </ListView.Behaviors>

        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <Label 
                        Text="{ Binding Name }"
                        VerticalTextAlignment="Center"
                        HorizontalTextAlignment="Center"
                        FontSize="16" />
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>

    </ListView>

Converter:

public class ItemTappedEventArgsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is ItemTappedEventArgs itemTappedEventArgs))
        {
            throw new ArgumentException("error");
        }

        return itemTappedEventArgs.Item;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Any ideas are welcome! Nothing worked for me.

Nanou Ponette
  • 1,372
  • 4
  • 22
  • 46

2 Answers2

0

i think you don't need to use CommandParameter,you could return the CategoryListItem.Id directly in your ItemTappedEventArgsConverter:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    if (!(value is ItemTappedEventArgs itemTappedEventArgs))
    {
        throw new ArgumentException("error");
    }

    return ((CategoryListItem)itemTappedEventArgs.Item).Id;
}

then in you ViewModel :

OnItemTappedCommand = new DelegateCommand<int>(OnItemTapped);

private async void OnItemTapped(int id)
{
  // here you could get the Id property
}
Leo Zhu
  • 15,726
  • 1
  • 7
  • 23
  • Good idea, but the converter is obfuscation. Just pass the tapped item to the command, and it can get itself the id or whatever needed. – Haukinger Aug 22 '19 at 09:30
  • @Haukinger yes,so i feel your needs a little strange,you could directly get the CategoryListItem data,if you want its Id,only need do like obj.Id,and you also could get the name like obj.Name and so on.. – Leo Zhu Aug 22 '19 at 09:35
  • @LeoZhu-MSFT I know but wouldn't it be better for performance only passing the Id when I don't need the whole object? – Nanou Ponette Aug 22 '19 at 09:57
  • @LeoZhu-MSFT I don't care for performance (right now), but for readability. Putting an unnecessary converter in a binding makes understanding the code more difficult. – Haukinger Aug 22 '19 at 10:46
  • @NanouPonette i think in your case it's negligible,but in any case,the idea of you optimize performance is good. – Leo Zhu Aug 22 '19 at 10:53
  • @NanouPonette so if you want only pass the id,you could do like above codes – Leo Zhu Aug 22 '19 at 10:55
  • With this solution I need to make an converter per list. Is there no general solution I can use for all my lists with different object types? – Nanou Ponette Aug 28 '19 at 09:23
0

I don't think you can bind to the tapped record from there. You might be able to do something in your ItemTemplate like create a behavior on the view cell and pass the property from there.

If you want to avoid the converter you could use "EventArgsParameterPath" instead:

           <b:EventToCommandBehavior 
            EventName="ItemTapped"
            Command="{Binding OnItemTappedCommand}"
            EventArgsParameterPath="Item">
        </b:EventToCommandBehavior>

Set it to "Item" and it will still send the entire CategoryListItem.

See documentation here: https://prismlibrary.github.io/docs/xamarin-forms/EventToCommandBehavior.html

djrpascu
  • 410
  • 4
  • 8