Search code examples
c#visual-studioxamarin.formsxamarin.android

Action When Clicking an Item of collection


I have FlexLayout that I use to display the contents of the collection. I want to realize the possibility that when you click on an element of the collection, the command is executed. I want to make sure that when you click on an item, another view is loaded that loads data that corresponds to the selected day. How do I get collection items to react to clicks?

<ContentPage.Resources>
    <DataTemplate x:Key="ColorItemTemplate">
        <Grid Margin="5"
              HeightRequest="120"
              WidthRequest="105">
            <BoxView Color="Azure" />
            <Label Text="{Binding Day}"
                   HorizontalOptions="Center"
                   VerticalOptions="Center" />
        </Grid>
    </DataTemplate>
</ContentPage.Resources>
<StackLayout Margin="10">
    <Label Text="CollectionView"
           FontSize="30"
           FontAttributes="Bold"
           HorizontalOptions="Center" />
    <Label Text="{Binding MyCollection.Count, StringFormat='Count: {0}'}" />
    <ScrollView>
        <FlexLayout Direction="Row" 
                        Wrap="Wrap"
                        AlignItems="Center"
                        AlignContent="Center"
                        BindableLayout.ItemsSource="{Binding MyCollection}"
                        BindableLayout.ItemTemplate="{StaticResource ColorItemTemplate}"/>
    </ScrollView>
</StackLayout>

Result

but when clicking on an item, where do you want to send data to?

In the screenshot above, you can see 20 objects in the collection. They are created in the class constructor and they display the time at which they were created.

PowerTrainings = new ObservableCollection<PowerTraining>();
            for (int i = 0; i < 20; i++)
            {
                PowerTrainings.Add(new PowerTraining() { DayOfTraining = dateTime });
            }

According to my idea, every time a user (in particular, I, because I do it for myself) will choose a particular day from the history, another view will be loaded, which will display the exercises that he did on that day. But how to correctly implement in the XAML code a code that will determine that this particular element of the collection was clicked (in which dates are displayed) and pass this date to another view, which, based on the property DayOfTraining , will make a query to the database with classes on this day and form another collection?


Solution

  • If I represent it by analogy with WPF, then I would create a MouseDoubleClick event and pass the object to another view through the SelectedIndex property. But in the case of Xamarin, I don't understand (yet) how everything works.

    I could deploy your app to my emulator, but when clicking on an item, where do you want to send data to?

    Depending on the scenario, there are several ways to pass data between two Views.

    A simple method is to use Xamarin.Forms MessagingCenter.

    The Xamarin.Forms MessagingCenter class implements the publish-subscribe pattern, allowing message-based communication between components that are inconvenient to link by object and type references. This mechanism allows publishers and subscribers to communicate without having a reference to each other, helping to reduce dependencies between them.

    Publish a message

    Publishers notify subscribers of a message with one of the MessagingCenter.Send overloads. The following code example publishes a Hi message:

    MessagingCenter.Send<MainPage>(this, "Hi");
    

    Subscribe to a message

    Subscribers can register to receive a message using one of the MessagingCenter.Subscribe overloads.

    MessagingCenter.Subscribe<MainPage> (this, "Hi", (sender) =>
    {
        // Do something whenever the "Hi" message is received
    });
    

    Unsubscribe from a message

    Subscribers can unsubscribe from messages they no longer want to receive. This is achieved with one of the MessagingCenter.Unsubscribe overloads:

    MessagingCenter.Unsubscribe<MainPage>(this, "Hi");
    

    Update:

    And I don't understand how you can find out which element the user clicked on

    You can add TapGestureRecognizer for your DataTemplate.

    I modified your DataTemplate and add TapGestureRecognizer for it. You can refer the following code:

    <ContentPage.Resources>
        <DataTemplate x:Key="ColorItemTemplate">
            <Frame Margin="5"
                  HeightRequest="120"
                  BackgroundColor="Azure"
                  WidthRequest="105">
                <Label Text="{Binding DayOfTraining}" 
                       HorizontalOptions="Center"
                       VerticalOptions="Center" />
    
                <Frame.GestureRecognizers>
                    <TapGestureRecognizer Command="{Binding BindingContext.TypeListSelectedCommand, Source={x:Reference flexLayout}}" CommandParameter="{Binding}"></TapGestureRecognizer>
                </Frame.GestureRecognizers>
            </Frame>
        </DataTemplate>
    </ContentPage.Resources>
    

    In class TrainingViewModel,add command TypeListSelectedCommand as follows:

        public ICommand TypeListSelectedCommand => new Command<PowerTraining>(selectedItem);
    
         void selectedItem(PowerTraining obj)
        {
            PowerTraining item = obj as PowerTraining;
    
            System.Diagnostics.Debug.WriteLine("clicked item = " + item.DayOfTraining);
        }
    

    Note: 1.flexLayout is the x:Name of your FlexLayout:

      <FlexLayout  x:Name="flexLayout"   />
    

    In addition, you can add TapGestureRecognizer like this:

    <ContentPage.Resources>
        <DataTemplate x:Key="ColorItemTemplate">
            <Frame Margin="5"
                  HeightRequest="120"
                  BackgroundColor="Azure"
                  WidthRequest="105">
                <Label Text="{Binding DayOfTraining}" 
                       HorizontalOptions="Center"
                       VerticalOptions="Center" />
    
                <Frame.GestureRecognizers>
                    <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"></TapGestureRecognizer>
                </Frame.GestureRecognizers>
            </Frame>
        </DataTemplate>
    </ContentPage.Resources>
    

    And in CalendarOfTraining.xaml.cs,add function TapGestureRecognizer_Tapped:

        private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
        {
            Frame boxView = sender as Frame;
            PowerTraining SelectedItem = (PowerTraining)boxView.BindingContext;
    
            System.Diagnostics.Debug.WriteLine(" clicked item = " + SelectedItem.DayOfTraining);
        }