7

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(() =>
            {
            });
        }
    }
}
John Livermore
  • 30,235
  • 44
  • 126
  • 216

6 Answers6

11

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}}"

Fabricio P.
  • 111
  • 1
  • 6
6

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

nevermore
  • 15,432
  • 1
  • 12
  • 30
2

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;
    ...
}
Bruno Caceiro
  • 7,035
  • 1
  • 26
  • 45
  • Thanks for that. However, I am using the FreshMVVM library which handles all the plumbing code you have above. This is a sample project, but in my main codebase all the bindings (including ICommands) work great. I have downloaded the CollectionView sample from the XF demo repo and am going through that to see if the problem is there as well. – John Livermore Jun 26 '19 at 14:42
2

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; }
1

It doesn't look like you set the SelectionMode property. According to the docs:

By default, CollectionView selection is disabled. However, this behavior can be changed by setting the SelectionMode property value to one of the SelectionMode enumeration members:

  • None – indicates that items cannot be selected. This is the default value.
  • Single – indicates that a single item can be selected, with the selected item being highlighted.
  • Multiple – indicates that multiple items can be selected, with the selected items being highlighted.

Adding SelectionMode = Single to the CollectionView will resolve your problem.

Andrew
  • 1,390
  • 10
  • 21
  • Good catch. I added the SelectionMode=Single, but I am still not getting the event. I updated my question with the new code and the repo. Any other things I am missing? – John Livermore Jun 26 '19 at 14:18
0

if you are using the Model for it you can use the following method

My C# Model View Class

public class MainView : INotifyPropertyChanged
{
    public ICommand SelectionChangedCommands => new Command<GroupableItemsView>((GroupableItemsView query) =>
    { 
        GO_Account test = query.SelectedItem as GO_Account; 
    });

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    } 
    
}

And this is my XAML

<CollectionView  x:Name="myAccounts" 
    SelectionMode="Single" 
    ItemsSource="{Binding Products}" 
    SelectionChangedCommand="{Binding SelectionChangedCommands}"
    SelectionChangedCommandParameter="{Binding Source={x:Reference myAccountsModel}}">
</CollectionView>
Sayed Muhammad Idrees
  • 1,245
  • 15
  • 25