Search code examples
c#xamarinbuttonxamarin.androidcollectionview

Button is not clickable in CollectionView


i have a CollectionView and my custom buttom. I want to make a grid with buttons.When I click on button it change a background color.I want to write in void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e) something AND that the text of label is Name(class field) of SELECTED button.When I click on buttons in collectionview it change color but button is not clickable,it does not see it,if I write image it can read data.Please help me make button clickable

<StackLayout>
                <Label  x:Name="meow1"></Label>
                <CollectionView  ItemsSource="{Binding Cars}" x:Name="phonesList" 
                         HeightRequest="90"
                         ItemsLayout="HorizontalList"
                        
                         BackgroundColor="Transparent"
                         SelectionMode="Single"
                         SelectionChanged="OnCollectionViewSelectionChanged">

                    <CollectionView.ItemTemplate>
                        <DataTemplate>
                        <Frame x:Name="frame" CornerRadius="10"  BackgroundColor="Black" Padding="0"    HeightRequest="90"
                       WidthRequest="95">
                                <Grid Padding="0" x:Name="meow">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto" />
                                        <RowDefinition Height="Auto" />
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto" />
                                        <ColumnDefinition Width="Auto" />
                                    </Grid.ColumnDefinitions>
                                <controls:CustomButton TintColor="#725762" HeightRequest="90"
                                                         WidthRequest="90" CornerRadius="10" HorizontalOptions="Center" 
                                                         BackgroundColor="White" ImageSource="{Binding ImagePath}" Clicked="Button_OnClicked"/>
                            </Grid>
                            </Frame>
                        </DataTemplate>
                    </CollectionView.ItemTemplate>
                </CollectionView>

            </StackLayout>

     void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e)
            {
               meow1.Text = (e.CurrentSelection.FirstOrDefault() as Car).NameImage;
        

}

Solution

  • Although not too much understanding the problem , but there is a suggestion about Button click event in CollectionView. We will use Command and CommandParameter of Button when binding model . And that is the design idea of MVVM.

    For example , the Xaml code modeified as follow:

    <StackLayout>
        <Label x:Name="meow1" 
               Text="{Binding SelectedCarItem.NameImage}"
               FontSize="Large"
               VerticalOptions="Start" 
               HorizontalOptions="CenterAndExpand" />
        <CollectionView  ItemsSource="{Binding Cars}"
                            x:Name="phonesList"
                            HeightRequest="90"
                            ItemsLayout="HorizontalList"
                            BackgroundColor="Transparent"
                            SelectionMode="Single"
                            SelectedItem="{Binding SelectedCarItem}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Frame x:Name="frame"
                            CornerRadius="10"
                            BackgroundColor="{Binding BgFrameColor}"
                            Padding="0"
                            HeightRequest="90"
                            WidthRequest="95">
                        <Grid Padding="0"
                                x:Name="meow">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <Button 
                                HeightRequest="90"
                                WidthRequest="90"
                                CornerRadius="10"
                                HorizontalOptions="Center"
                                BackgroundColor="{Binding BgButtonColor}"
                                ImageSource="{Binding ImagePath}"
                                Command="{Binding TapCommand}"
                                CommandParameter="{Binding Source={x:Reference frame}, Path=BindingContext}" />
                        </Grid>
                    </Frame>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
    

    Then need to modify the Car model , adding BgColor,IsSelected and TapCommand property:

    public class Car : INotifyPropertyChanged
    {
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        public string NameImage { get; set; } 
        public string ImagePath { get; set; }
    
        private Color bgFrameColor;
    
        public Color BgFrameColor
        {
            set
            {
                if (bgFrameColor != value)
                {
                    bgFrameColor = value;
                    OnPropertyChanged("BgFrameColor");
                }
            }
            get
            {
                return bgFrameColor;
            }
        }
    
        private Color bgButtonColor;
    
        public Color BgButtonColor
        {
            set
            {
                if (bgButtonColor != value)
                {
                    bgButtonColor = value;
                    OnPropertyChanged("BgButtonColor");
                }
            }
            get
            {
                return bgButtonColor;
            }
        }
    
        private bool isSelected;
    
        public bool IsSelected
        {
            set
            {
                if (isSelected != value)
                {
                    isSelected = value;
                    OnPropertyChanged("IsSelected");
                }
            }
            get
            {
                return isSelected;
            }
        }
    
        public ICommand TapCommand
        {
            get
            {
                return new Command((e) =>
                {
                    var item = (e as Car);
                    // logic on item
                    if (item.isSelected)
                    {
                        item.isSelected = false;
                        item.BgButtonColor = Color.White;
                        item.BgFrameColor = Color.Black;
                        PageCollectionView.SelectedCar.Remove(item);
                        MessagingCenter.Send<object, Car>(this, "Hi", new Car() {NameImage ="Welcome to the car home!" });
                    }
                    else
                    {
                        item.isSelected = true;
                        item.BgButtonColor = Color.Blue;
                        item.BgFrameColor = Color.Yellow;
                        if (PageCollectionView.SelectedCar.Count == 0)
                        {
                            PageCollectionView.SelectedCar.Add(item);
                        }
                        else
                        {
                            PageCollectionView.SelectedCar[0].isSelected = false;
                            PageCollectionView.SelectedCar[0].BgButtonColor = Color.White;
                            PageCollectionView.SelectedCar[0].BgFrameColor = Color.Black;
                            PageCollectionView.SelectedCar.Remove(PageCollectionView.SelectedCar[0]);
                            PageCollectionView.SelectedCar.Add(item);
                        }
                        MessagingCenter.Send<object, Car>(this, "Hi", item);
                    }
    
                });
            }
        }
    
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    Add CarModel class to load data :

    public class CarModel: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        public List<Car> Cars { get; set; }
    
        //public static Car SelectedCarItem { set; get; }
        public CarModel()
        {
            Cars = new List<Car>();
            Cars.Add(new Car() { NameImage = "Lexus", ImagePath = "Lexus.png", BgButtonColor = Color.White, BgFrameColor = Color.Black, IsSelected = false }); ;
            Cars.Add(new Car { NameImage = "Audi", ImagePath = "Audi.png", BgButtonColor = Color.White, BgFrameColor = Color.Black, IsSelected = false });
            // set default text of label 
            selectedCarItem = new Car() { NameImage = "Welcome to the car home!" };
        }
    
        private Car selectedCarItem;
        public Car SelectedCarItem
        {
            get
            {
                return selectedCarItem;
            }
            set
            {
                if (selectedCarItem != value)
                {
                    selectedCarItem = value;
                    OnPropertyChanged("SelectedCarItem");
                }
            }
        }
    
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    Now in ContentPage , declare a List<Car> to store only one item to keep this collection view is single selected. And use MessagingCenter to update carModel.SelectedCarItem here:

    public partial class PageCollectionView : ContentPage
    {
        public static List<Car> SelectedCar { get; set; }
    
        public PageCollectionView()
        {
            InitializeComponent();
    
            CarModel carModel = new CarModel();
            BindingContext = carModel;
    
            SelectedCar = new List<Car>();
    
            MessagingCenter.Subscribe<object,Car>(this, "Hi", (sender,arg) =>
            {
                // Do something whenever the "Hi" message is received
                carModel.SelectedCarItem = arg;
            });
    
        }
    
    }
    

    The effect as follow :

    enter image description here

    Note: From the sample , you will see that using binding to modify BackgroundColor and Model Data. Therefore, it's not recommanded to use OnCollectionViewSelectionChanged to modify text of Lable .