How to make a row in a list after clicking a buttom xaml

76 Views Asked by At

I want to make a fitness app which keeps your workouts. Im trying to make a list in which you can add your exercises and sets reps and weight but it didnt work. I tried to make a counter (sets) which increments every time the button is pressed but didnt manage to. View


  
        <!-- Display ExerciseTypeGroups -->
        <ListView ItemsSource="{Binding ExerciseTypeGroups}" HasUnevenRows="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <!-- Display ExerciseType of the group -->
                        <StackLayout Margin="0,0,0,0">
                            <Label Text="{Binding ExerciseType.Name}" FontSize="25" Padding="10" />
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>

                                <!-- Entry for Reps -->
                                <Entry Grid.Column="0" Placeholder="Reps" Keyboard="Numeric" Text="{Binding NewExerciseReps}" />

                                <!-- Entry for Volume -->
                                <Entry Grid.Column="1" Placeholder="Volume" Keyboard="Numeric" Text="{Binding NewExerciseVolume}" />

                                <!-- Button to add exercise to the group -->
                                <Button Grid.Column="2" Text="Complete" Command="{Binding CompleteExerciseCommand}" />
                            </Grid>
                            <Button Grid.Column="1" Text="Add Exercise" Command="{Binding AddExerciseToGroupCommand}" VerticalOptions="End"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

ViewModel

 public ICommand AddExerciseToGroupCommand => new Command(AddExerciseToGroup);

 private void AddExerciseToGroup()
 {
    
     OnPropertyChanged(nameof(ExerciseTypeGroups));
 }

Thats the current state of the app but when i click add exercise it does not add exercise

1

There are 1 best solutions below

12
Liqun Shen-MSFT On

The Button is defined in DataTemplate in a ListView. Thus, the BindingContext of the Button is not the WorkoutViewModel. In this case, you should use Relative Bindings or x:Reference expressions.

Option 1 Use Relative Bindings

If you use Relative Bindings, you may refer to Relative bindings.

For xaml page

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Muscles_app.Views.WorkoutPage"
             xmlns:ViewModels="clr-namespace:Muscles_app.ViewModels" 
             xmlns:Models ="clr-namespace:Muscles_app.Models" 
             BackgroundColor="White" x:Name="Workouts">


<ContentPage.BindingContext>
    <ViewModels:WorkoutViewModel />
</ContentPage.BindingContext>


    <StackLayout>
        <ListView ItemsSource="{Binding ExerciseTypeGroups}" HasUnevenRows="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <!-- Display ExerciseType of the group -->
                        <StackLayout Margin="0,0,0,0">
                            <Label Text="{Binding Name}" FontSize="25" Padding="10" />
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>

                                <!-- Entry for Reps -->
                                <Entry Grid.Column="0" Placeholder="Reps" Keyboard="Numeric" Text="{Binding NewExerciseReps}" />

                                <!-- Entry for Volume -->
                                <Entry Grid.Column="1" Placeholder="Volume" Keyboard="Numeric" Text="{Binding NewExerciseVolume}" />

                                <!-- Button to add exercise to the group -->
                                <Button Grid.Column="2" Text="Complete" Command="{Binding Source={RelativeSource AncestorType={x:Type ViewModels:WorkoutViewModel}}, Path=CompleteExerciseCommand}" /> />
                            </Grid>
                            <Button Grid.Column="1" Text="Add Exercise" Command="{Binding Source={RelativeSource AncestorType={x:Type ViewModels:WorkoutViewModel}}, Path=AddExerciseToGroupCommand}" VerticalOptions="End"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

for code behind, Note: If you add BindingContext in XAML, then don't add it again in code behind.

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        //this.BindingContext = new WorkoutViewModel();
    }
}

Option 2 Use x:reference

You could also use x:reference Binding expression to achieve,

The only difference from Option 1 is for XAML part.

First we define the name for our page,

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             ...
             x:Name="Workouts"> 

Then make some changes for the button command binding,

    <StackLayout>
        <ListView ItemsSource="{Binding ExerciseTypeGroups}" HasUnevenRows="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <!-- Display ExerciseType of the group -->
                        ...
                                <!-- Button to add exercise to the group -->
                            <Button Grid.Column="2" Text="Complete" Command="{Binding BindingContext.CompleteExerciseCommand, Source={x:Reference Workouts}}" />
                        </Grid>
                        <Button Grid.Column="1" Text="Add Exercise" Command="{Binding BindingContext.AddExerciseToGroupCommand, Source={x:Reference Workouts}}" VerticalOptions="End"/>
                    </StackLayout>
       ...
        </ListView>

    </StackLayout>

For more info, you may refer to Xamarin.Forms Relative Bindings, XAML Namespaces in Xamarin.Forms

Hope it helps!