Xamarin 表单:如何仅为 Collectionview 中的选定项目添加下划线

Xamarin forms: How to add an underline only for the selected item in Collectionview

我有一个 horizontal collectionview 和一些项目,我只需要为所选项目添加下划线。

我试过如下:

MainPage.xaml.cs

public partial class MainPage : ContentPage
{
    public List<Category> categoryList { get; set; }
    public MainPage()
    {
        InitializeComponent();
        categoryList = new List<Category>();
        SetItems(true, false, false, false, false, false);
    }

    private void SetItems(bool v1, bool v2, bool v3, bool v4, bool v5, bool v6)
    {
        categoryList.Add(new Category() { Title = "itme1", IsSelected = v1 });
        categoryList.Add(new Category() { Title = "itme2", IsSelected = v2 });
        categoryList.Add(new Category() { Title = "itme3", IsSelected = v3 });
        categoryList.Add(new Category() { Title = "itme4", IsSelected = v4 });
        categoryList.Add(new Category() { Title = "itme5", IsSelected = v5 });
        categoryList.Add(new Category() { Title = "itme6", IsSelected = v6 });
        Category_collectionview.ItemsSource = categoryList;
    }

    public void CategoryTapped(object sender, SelectionChangedEventArgs e)
    {
        var selectedItem = (e.CurrentSelection.FirstOrDefault() as Category);
        if (selectedItem != null)
        {
            if (selectedItem.Title == "itme1")
            {
                SetItems(true, false, false, false, false, false);
            }
            else if (selectedItem.Title == "itme2")
            {
                SetItems(false, true, false, false, false, false);
            }
            else if (selectedItem.Title == "itme3")
            {
                SetItems(false, false, true, false, false, false);
            }
        }
        Category_collectionview.SelectedItem = null;
    }
}

public class Category 
{
    public string Title { get; set; }
    public bool IsSelected { get; set; }
}

MainPage.xaml

<CollectionView 
        SelectionMode="Single"
        SelectionChanged="CategoryTapped"
        x:Name="Category_collectionview"
        ItemsLayout="HorizontalList">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <StackLayout 
                    Orientation="Vertical"
                    Margin="5">

                    <Label
                        TextColor="Black"
                        HorizontalTextAlignment="Center"
                        VerticalTextAlignment="Center"
                        Text="{Binding Title}">
                        <Label.FontSize>
                            <OnIdiom x:TypeArguments="x:Double">
                                <OnIdiom.Phone>16</OnIdiom.Phone>
                                <OnIdiom.Tablet>32</OnIdiom.Tablet>
                                <OnIdiom.Desktop>16</OnIdiom.Desktop>
                            </OnIdiom>
                        </Label.FontSize>
                    </Label>

                    <BoxView 
                        HorizontalOptions="FillAndExpand"
                        BackgroundColor="Black"
                        IsVisible="{Binding IsSelected}"
                        HeightRequest="2"/>
                </StackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

但是 boxview 总是在第一项上,我在这里缺少什么?

您需要在模型中实现接口 INotifyPropertyChanged,以便您可以在运行时更新 UI

public class Category : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;



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

    public string Title { get; set; }

    bool isSelected;
    public bool IsSelected { get {

            return isSelected;

        }
        set
        {
            if(value!= isSelected)
            {
                isSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }
    }
}

此外,CategoryTapped 事件对您的情况无效。您可以使用 TapGestureRecognizer

<CollectionView 
        SelectionMode="Single"
        
        x:Name="Category_collectionview"
        ItemsSource="{Binding categoryList}"
        ItemsLayout="HorizontalList">
            <CollectionView.ItemTemplate>
<DataTemplate>
     <StackLayout 
           Orientation="Vertical"
           Margin="5">

          <StackLayout.GestureRecognizers>
             <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
          </StackLayout.GestureRecognizers>
          //...

在后面的代码中

注意: 最好使用 ObservableCollection 而不是 List 。而且每次都重新设置 ItemsSource 并不是一个好的设计。

public partial class MainPage : ContentPage
    {
        public ObservableCollection<Category> categoryList { get; set; }
        public MainPage()
        {
            InitializeComponent();
            categoryList = new ObservableCollection<Category>();
            SetItems(true, true, false, false, false, false);
            BindingContext = this;
        }

        private void SetItems(bool v1, bool v2, bool v3, bool v4, bool v5, bool v6)
        {
            categoryList.Add(new Category() { Title = "itme1", IsSelected = v1 });
            categoryList.Add(new Category() { Title = "itme2", IsSelected = v2 });
            categoryList.Add(new Category() { Title = "itme3", IsSelected = v3 });
            categoryList.Add(new Category() { Title = "itme4", IsSelected = v4 });
            categoryList.Add(new Category() { Title = "itme5", IsSelected = v5 });
            categoryList.Add(new Category() { Title = "itme6", IsSelected = v6 });
            Category_collectionview.ItemsSource = categoryList;
           
        }

        private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
        {
            var obj = sender as StackLayout;

            var currentItems = obj.BindingContext as Category;

            foreach (Category category in categoryList)
            {
                category.IsSelected = false;

                if (currentItems == category)
                {
                    category.IsSelected = true;
                }
            }

            Category_collectionview.SelectedItem = null;
        }
    }