Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin forms pass clicked item to command as command parameter

I just started with Xamarin forms an now I have a list of items that I display in a custom template.

The behavior that i want is that the event fired on the context of the page (using Corcav.Behaviors), but I want to pass the clicked item to the command. I can't seem to get the last part to work. With the below implementation the event fires correctly but the passed parameter is the MyEventsListModel but I want the item that is clicked.

note I preferably am want a solution in xaml/viewmodel and not in the code-behind. And alternate solution where both events fire on the Event is also fine.

Xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:behaviors="clr-namespace:Corcav.Behaviors;assembly=Corcav.Behaviors"
             x:Class="TheEventsApp.Mobile.MyEventsList"
             Title="My Events"
             x:Name="MainPage">
    <ListView ItemsSource="{Binding Events}">
        <behaviors:Interaction.Behaviors>
            <behaviors:BehaviorCollection>
                <behaviors:EventToCommand EventName="ItemTapped" Command="{Binding NavigateToEventDetails}" CommandParameter="{Binding .}" />
            </behaviors:BehaviorCollection>
        </behaviors:Interaction.Behaviors>
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Orientation="Vertical">
                        <Label Text="{Binding Name}" />
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>

Viewmodel:

 [ImplementPropertyChanged]
 public class MyEventsListModel : FreshBasePageModel
 { 
    private readonly EventsDatastore eventsStore;

    public MyEventsListModel(EventsDatastore eventsStore)
    {
        this.eventsStore = eventsStore;
    }

    protected async override void ViewIsAppearing(object sender, EventArgs e)
    {
        this.Events = await eventsStore.GetMyEventsAsync();
    }

    public ObservableCollection<Event> Events { get; set; } = new ObservableCollection<Event>();

    public Command NavigateToEventDetails
    {
        get
        {
            return new Command(async (clickedEvent) =>
            {
                await CoreMethods.PushPageModel<EventDetailsPageModel>(clickedEvent);
            });
        }
    }
}
like image 949
Patrick Avatar asked Feb 24 '17 12:02

Patrick


1 Answers

The solution was fairly simple. After diving into the sourcecode of Corcav it was easy enough to figure it out. The following code in EventToCommand.cs

private void OnFired(EventArgs e)
{
    object param = this.PassEventArgument ? e : this.CommandParameter;

    if (!string.IsNullOrEmpty(this.CommandName))
    {
        if (this.Command == null) this.CreateRelativeBinding();
    }

    if (this.Command == null) throw new InvalidOperationException("No command available, Is Command properly set up?");

    if (e == null && this.CommandParameter == null) throw new InvalidOperationException("You need a CommandParameter");

    if (this.Command != null && this.Command.CanExecute(param))
    {
        this.Command.Execute(param);
    }
}

Handles it. Simply setting "PassEventArgument" to true solved the issue for me.

<behaviors:EventToCommand EventName="ItemTapped" Command="{Binding NavigateToEventDetails}" PassEventArgument="True" />
like image 158
Patrick Avatar answered Sep 30 '22 17:09

Patrick