Xamarin Forms - SelectionChangedCommand 没有为 CollectionView 触发

Xamarin Forms - SelectionChangedCommand not firing for CollectionView

下面的代码显示了 CollectionView 的一个简单示例。我没有收到 SelectionChangedCommand 的事件。有人能看出我做错了什么吗?

顺便说一句,可以在 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(() =>
            {
            });
        }
    }
}

您似乎没有设置 SelectionMode 属性。根据 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.

SelectionMode = Single 添加到 CollectionView 将解决您的问题。

如果你想使用你的 ViewModel,那么你应该使用 SelectedItem 的绑定:

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

并且,在您的 ViewModel 中:

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

所以每次 select 一个新对象时,SelectedMonkey 都会更新。

如果你想跟踪 SelectionChanged,那么,它应该在 code-behind 中(不确定如何在视图模型中实现,文档中没有相关内容)

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

并且,在您的 Page.xaml.cs 中:

void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var previous = e.PreviousSelection;
    var current = e.CurrentSelection;
    ...
}

我使用你的代码并在我这边创建了一个演示,我添加了 widthRequestHeightRequest 以使 collectionView 工作:

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

在我单击 CollectionView 中的不同项目后确实触发了 SelectionChangedCommand

我在这里上传了一个样本,你可以查看:collectionView-selectItemChanged-xamarin.forms

我身边的一些事情(除了 SelectionMode = Single):

  • 确保您的命令签名在您的 PageModel 中是 <object> 并根据您的需要进行任何转换(特别是如果您的集合变得更复杂)。

  • 另外,在您的 XAML 中,您想为 CollectionView 命名并使用 SelectedItem 属性。 SelectionChangedCommandParameter="{Binding SelectedItem, Source={x:Reference cvTagsCollectionView}}"

如果你正在使用它的模型,你可以使用下面的方法

我的 C# 模型视图 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));
    } 
    
}

这是我的 XAML

<CollectionView  x:Name="myAccounts" 
    SelectionMode="Single" 
    ItemsSource="{Binding Products}" 
    SelectionChangedCommand="{Binding SelectionChangedCommands}"
    SelectionChangedCommandParameter="{Binding Source={x:Reference myAccountsModel}}">
</CollectionView>

我改进了 Fabricio P. 的回答:

  • 将 {RelativeSource Self} 用于 SelectionChangedCommandParameter。它有助于省略命名集合视图。

所以你的 xaml 部分将是这样的:


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

并且在您的视图模型中:

public ICommand SelectObjectCommand => new Command<string>(i => { Debug.WriteLine("Selected: " + i); });
public IEnumerable<string> Objects { get; set; }