Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin Forms - SelectionChangedCommand not firing for CollectionView

The code below shows a simple example of a CollectionView. I am not receiving the event for the SelectionChangedCommand. Can someone see what I am doing wrong?

btw, the complete source for this can be found on GitHub here.

MainPage.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:local="clr-namespace:ControlDemo"
                 x:Class="ControlDemo.MainPage">

    <StackLayout>
        <CollectionView SelectionMode ="Single"
                        ItemsSource="{Binding Tags}"
                        SelectionChangedCommand="{Binding SelectedTagChanged}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout>
                        <Label Text="{Binding .}" />
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>

</ContentPage>

MainPageModel.cs

public class MainPageModel : FreshBasePageModel
{
    public override void Init(object initData)
    {
        Tags = new List<string>() { "A", "B", "C" };
        base.Init(initData);
    }

    public List<string> Tags { get; set; }

    public Command SelectedTagChanged
    {
        get
        {
            return new Command(() =>
            {
            });
        }
    }
}
like image 300
John Livermore Avatar asked Jun 26 '19 13:06

John Livermore


4 Answers

Couple of things that worked at my side (additionally to the SelectionMode = Single):

  • Make sure your Command' signature is <object> at your PageModel and do any cast according to your needs (specially if your collection becomes more complex).

  • Also at your XAML you want to give your CollectionView a name and use the SelectedItem property. SelectionChangedCommandParameter="{Binding SelectedItem, Source={x:Reference cvTagsCollectionView}}"

like image 93
Fabricio P. Avatar answered Nov 17 '22 14:11

Fabricio P.


I use your code and created a demo on my side, I add the widthRequest and HeightRequest to make the collectionView work:

 <CollectionView            
              HeightRequest="170" 
              WidthRequest="200"                        
              SelectionMode="Single" 
              SelectionChangedCommand="{Binding SelectedTagChangedCommand}"
              ItemsSource="{Binding Tags}"      
         >

The SelectionChangedCommand did triggered after I click different items in the CollectionView.

I uploaded a sample here and you can check it: collectionView-selectItemChanged-xamarin.forms

like image 23
nevermore Avatar answered Nov 17 '22 14:11

nevermore


If you want to use your ViewModel, then you should use the Binding for the SelectedItem:

<CollectionView ItemsSource="{Binding Monkeys}"
                SelectionMode="Single"
                SelectedItem="{Binding SelectedMonkey, Mode=TwoWay}">
    ...
</CollectionView>

and, in your ViewModel:

Monkey selectedMonkey;
    public Monkey SelectedMonkey
    {
        get
        {
            return selectedMonkey;
        }
        set
        {
            if (selectedMonkey != value)
            {
                selectedMonkey = value;
            }
        }
    }

So everytime you select a new object, the SelectedMonkey will be updated.

If you want to track the SelectionChanged, then, it should be in the code-behind (not sure how to implement within the viewmodel, nothing about that in the docs)

<CollectionView ItemsSource="{Binding Monkeys}"
                SelectionMode="Single"
                SelectionChanged="OnCollectionViewSelectionChanged">
    ...
</CollectionView>

And, in your Page.xaml.cs:

void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var previous = e.PreviousSelection;
    var current = e.CurrentSelection;
    ...
}
like image 2
Bruno Caceiro Avatar answered Nov 17 '22 12:11

Bruno Caceiro


I improved Fabricio P. answer in this way:

  • Used {RelativeSource Self} for SelectionChangedCommandParameter. It helps to omit named collection views.

So your xaml part will be something like this:


<CollectionView
    ItemsSource="{Binding Objects}"
    SelectionMode="Single"
    SelectionChangedCommand="{Binding SelectObjectCommand}"
    SelectionChangedCommandParameter="{Binding SelectedItem, Source={RelativeSource Self}}">

And in your view model:

public ICommand SelectObjectCommand => new Command<string>(i => { Debug.WriteLine("Selected: " + i); });
public IEnumerable<string> Objects { get; set; }
like image 2
Tymur Tkachenko Avatar answered Nov 17 '22 13:11

Tymur Tkachenko