Command doesn't trigger

Eduardo Gomez 4,156 Reputation points
2025-12-13T21:53:04.53+00:00
<?xml version="1.0" encoding="utf-8" ?>
<syncfusion:SfPopup
    x:Class="Scan2Cart.Views.PopUps.CartPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:const="clr-namespace:Scan2Cart.Constants"
    xmlns:controls="clr-namespace:Scan2Cart.Controls"
    xmlns:model="clr-namespace:Scan2Cart.Models"
    xmlns:picker="clr-namespace:Syncfusion.Maui.Picker;assembly=Syncfusion.Maui.Picker"
    xmlns:syncfusion="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
    xmlns:vm="clr-namespace:Scan2Cart.ViewModels"
    Padding="20"
    x:DataType="vm:HomePageViewModel"
    AnimationMode="Zoom"
    IsFullScreen="True"
    ShowCloseButton="True"
    ShowHeader="False"
    StaysOpen="True">

    <syncfusion:SfPopup.ContentTemplate>
        <DataTemplate x:DataType="vm:HomePageViewModel">
            <Grid
                Padding="10"
                RowDefinitions="40, *, 40"
                RowSpacing="5">
                <Label FontSize="Large" Text="Your cart" />
                <Label
                    FontAttributes="Bold"
                    FontFamily="la"
                    FontSize="30"
                    HorizontalTextAlignment="End"
                    Text="{x:Static const:IconFont.WindowClose}"
                    TextColor="Red">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Command="{x:Binding HideCartCommand}" />
                    </Label.GestureRecognizers>
                </Label>
                <CollectionView Grid.Row="1" ItemsSource="{x:Binding Products}">
                    <CollectionView.ItemsLayout>
                        <LinearItemsLayout ItemSpacing="10" Orientation="Vertical" />
                    </CollectionView.ItemsLayout>
                    <CollectionView.ItemTemplate>
                        <DataTemplate x:DataType="model:Product">
                            <Border>
                                <Grid
                                    Padding="2"
                                    ColumnDefinitions="60,*,70"
                                    ColumnSpacing="5">
                                    <Image
                                        HeightRequest="60"
                                        HorizontalOptions="Start"
                                        Source="{x:Binding ImageUrl}"
                                        WidthRequest="60" />
                                    <VerticalStackLayout Grid.Column="1">
                                        <Label
                                            FontAttributes="Bold"
                                            FontSize="10"
                                            Text="{x:Binding Name}" />
                                        <Label FontSize="10" Text="{x:Binding Description}" />
                                        <Label
                                            Margin="0,10,0,0"
                                            FontAttributes="Bold"
                                            Text="{x:Binding Price}" />
                                    </VerticalStackLayout>
                                    <Button
                                        Grid.Column="2"
                                        BackgroundColor="Transparent"
                                        Command="{Binding OpenQuantityPopUpCommand, Source={x:RelativeSource AncestorType={x:Type vm:HomePageViewModel}}}"
                                        CommandParameter="{x:Binding .}"
                                        FontAttributes="Bold"
                                        FontSize="14"
                                        Text="{x:Binding SelectedQuantity}"
                                        TextColor="{x:AppThemeBinding Dark={x:StaticResource White},
                                                                      Light={x:StaticResource Black}}" />
                                </Grid>
                                <Border.StrokeShape>
                                    <RoundRectangle CornerRadius="8" />
                                </Border.StrokeShape>
                            </Border>
                        </DataTemplate>
                    </CollectionView.ItemTemplate>
                </CollectionView>
                <picker:SfPicker
                    IsOpen="False"
                    IsVisible="False"
                    Mode="Dialog"
                    TextDisplayMode="FadeAndShrink">
                    <picker:SfPicker.Columns>
                        <picker:PickerColumn
                            HeaderText="Select quantity"
                            ItemsSource="{x:Binding Product.QuantityRange}"
                            SelectedItem="{x:Binding Product.SelectedQuantity}" />
                    </picker:SfPicker.Columns>
                </picker:SfPicker>
                <Label
                    Grid.Row="2"
                    FontSize="30"
                    HorizontalTextAlignment="Start"
                    Text="Total" />
                <Label
                    Grid.Row="2"
                    FontSize="30"
                    HorizontalTextAlignment="End"
                    Text="{x:Binding CartTotal}" />
            </Grid>
        </DataTemplate>
    </syncfusion:SfPopup.ContentTemplate>

    <syncfusion:SfPopup.PopupStyle>
        <syncfusion:PopupStyle
            CornerRadius="0"
            HasShadow="True"
            HeaderBackground="{x:AppThemeBinding Dark='#C8000000',
                                                 Light='#00000'}"
            MessageBackground="{x:AppThemeBinding Dark='#C8000000',
                                                  Light='#C6626161'}" />
    </syncfusion:SfPopup.PopupStyle>
</syncfusion:SfPopup>


namespace Scan2Cart.ViewModels;

public partial class HomePageViewModel(IPageService pageService, IDataProvider dataProvider) : BaseViewModel(pageService) {

    private bool _isPopupOpening;

    private DateTime _lastAlertTime = DateTime.MinValue;

    #region ObservableProperties

    [ObservableProperty]
    public partial bool IsSelectedQtyPopopOpened { get; set; }

    [ObservableProperty]
    public partial bool IsCartPopopOpen { get; set; }

    [ObservableProperty]
    public partial bool ShouldDetect { get; set; } = true;

    [ObservableProperty]
    public partial bool IsProductInfoVisible { get; set; } = false;

    [ObservableProperty]
    public partial Product? Product { get; set; }

    [ObservableProperty]
    public partial bool IsPopUpDetectedOpen { get; set; }

    [ObservableProperty]
    public partial decimal CartTotal { get; set; }

    public ObservableCollection<Product> Products { get; set; } = [];

    #endregion

    private void RecalculateCartTotal() {
        CartTotal = Products.Sum(p => p.Total);
    }

    private void AddProduct(Product p) {
        p.PropertyChanged += (s, e) => {
            if (e.PropertyName == nameof(Product.Total))
                RecalculateCartTotal();
        };

        Products.Add(p);
        RecalculateCartTotal();
    }



    [RelayCommand]
    private async Task BarcodesDetected(IEnumerable<BarcodeResult> results) {

        if (_isPopupOpening) return;

        var val = results.FirstOrDefault()?.Value;
        if (string.IsNullOrEmpty(val)) return;

        _isPopupOpening = true;

        Product = await dataProvider.GetProductByIdAsync(val);

        if (Product is null) {

            //await ShowProductNotFoundAlertAsync();
            //_isPopupOpening = false;
            //return;

            AddProduct(new Product {
                Id = "DUMMY001",
                Name = "Test Product",
                Price = 9.99M,
                Description = "This is a placeholder product for testing.",
                ImageUrl = "https://via.placeholder.com/150",
                Quantity = 10,
                SelectedQuantity = 1,              // initialize
                Total = 9.99M                      // Price × SelectedQuantity
            });

            AddProduct(new Product {
                Id = "TEST001",
                Name = "Coffee Beans",
                Price = 5.00M,
                Description = "Premium roasted coffee beans",
                ImageUrl = "https://via.placeholder.com/150",
                Quantity = 20,
                SelectedQuantity = 1,
                Total = 5.00M
            });

            AddProduct(new Product {
                Id = "TEST002",
                Name = "Milk Carton",
                Price = 2.50M,
                Description = "Organic whole milk",
                ImageUrl = "https://via.placeholder.com/150",
                Quantity = 15,
                SelectedQuantity = 1,
                Total = 2.50M
            });
        }

        await Task.Delay(100);

        MainThread.BeginInvokeOnMainThread(() => {
            IsProductInfoVisible = true;
            IsPopUpDetectedOpen = true;
        });

        _isPopupOpening = false;
    }

    [RelayCommand]
    void Yes() {

        // Add product if not already in the list
        if (!Products.Any(x => x.Id == Product?.Id))
            AddProduct(Product!);

        // Close popup and reset flags
        IsPopUpDetectedOpen = false;
        ShouldDetect = true;
    }

    [RelayCommand]
    void No() {

        IsPopUpDetectedOpen = false;
        ShouldDetect = true;
    }

    [RelayCommand]
    async Task OpenProductPopop() {

        ShouldDetect = false;
    }

    [RelayCommand]
    void CloseProductPopop() {

        IsProductInfoVisible = false;
        IsPopUpDetectedOpen = false;
        ShouldDetect = true;
    }
    [RelayCommand]
    async Task ShowCart() {

        ShouldDetect = false;
        IsCartPopopOpen = true;
    }

    [RelayCommand]
    async Task HideCart() {

        IsCartPopopOpen = false;
        ShouldDetect = true;
    }

    [RelayCommand]
    void OpenQuantityPopUp(Product p) {

        IsSelectedQtyPopopOpened = true;
    }

    private async Task ShowProductNotFoundAlertAsync() {
        var now = DateTime.UtcNow;
        if ((now - _lastAlertTime).TotalSeconds < 3) return;
        _lastAlertTime = now;

        await MainThread.InvokeOnMainThreadAsync(async () => {
            await DisplayAlertAsync("Error", "It looks like this item does not exist in your database", "OK");
        });
    }

}

Developer technologies | .NET | .NET MAUI
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Jack Dang (WICLOUD CORPORATION) 5,960 Reputation points Microsoft External Staff Moderator
    2025-12-15T04:57:23.39+00:00

    Hi @Eduardo Gomez ,

    Thanks for reaching out.

    Based on the code you provided, the reason your button didn’t trigger the quantity picker is due to a few issues in your ViewModel and XAML:

    1. Typo in the command name Your ViewModel method was named OenQuantityPopUp, but the generated command that the Button binds to is OpenQuantityPopUpCommand. Because of the typo, the command didn’t exist, so the Button had nothing to execute.
    2. Passing the selected product Inside the CollectionView, the Button needs to know which Product it should act on. Your Picker binds to Product.QuantityRange in the ViewModel, but without setting Product to the tapped item, it couldn’t show the correct quantity.
    3. Reference to the popup You were using {x:Reference CartPage} in your Button binding, but the root SfPopup had no x:Name, so the reference binding failed.

    Fixes applied:

    • Renamed the command method to OpenQuantityPopUp and accepted a Product parameter:
    [RelayCommand]
    void OpenQuantityPopUp(Product product)
    {
        if (product is not null)
        {
            Product = product; // Set VM product to tapped item
        }
        IsSelectedQtyPopopOpened = true;
    }
    
    • Updated the Button binding in XAML to pass the tapped product:
    <Button
        Grid.Column="2"
        BackgroundColor="Transparent"
        Command="{Binding Source={x:Reference CartPage}, Path=BindingContext.OpenQuantityPopUpCommand}"
        CommandParameter="{Binding .}"
        FontAttributes="Bold"
        FontSize="14"
        Text="{x:Binding SelectedQuantity}" />
    

    Hope this helps! If my answer was helpful - kindly follow the instructions here so others with the same problem can benefit as well.


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.