0
votes

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;
        

}
1
you cannot reference elements in a template by name. You need to modify the underlying model object that the element is bound to. And if you want an action to happen on button click, you need to use a Clicked handler, not SelectionChanged. SelectionChanged will fire for any tap event in the Cell, not just button taps. - Jason
where is the code for Button_OnClicked? Is it firing when you click the button? - Jason
your question says "Button is not clickable" but in your comment it says that "it works". I don't understand what the actual problem is that you are trying to solve. - Jason
@MariaKamenskyh Hi ,welcome to SO! Could you share an image to explain the problem , that will be clear to understand what your wants. - Junior Jiang

1 Answers

4
votes

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 .