AgentRed
AgentRed

Reputation: 72

Xamarin Forms - How to populate ListView from the data you entered?

Process:

Step 1: In Food menu you can select you want to order , if you tapped it quantity popup will show

image of OrdernowMenu.xaml

OrdernowMenu

Link:https://i.sstatic.net/qqPUD.jpg

OrdernowMenu.xaml

  <ContentPage.ToolbarItems>
        <ToolbarItem Icon="cartimage.png" Clicked="ToolbarItem_Clicked"></ToolbarItem>

    </ContentPage.ToolbarItems>

    <ListView x:Name="MyOrder" ItemSelected="MyOrder_ItemSelected" RowHeight="100">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <Grid ColumnSpacing="0" RowSpacing="0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <StackLayout Grid.Row="0" Grid.Column="0" >
                            <Image Source="{Binding menu_image ,StringFormat='https://i.imgur.com/{0:F0}.png'}"  Aspect="AspectFill"/>
                        </StackLayout>
                        <StackLayout Grid.Row="0" Grid.Column="1" VerticalOptions="Center">
                            <Label Text="{Binding menu_name}" Font="30"/>
                            <Label Text="{Binding menu_price,StringFormat='₱ {0:F0}'}" Font="20"/>
                            <Label Text="{Binding menu_availability} " Font="10" />
                        </StackLayout>
                    </Grid>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

OrdernowMenu.xaml.cs

public partial class OrdernowMenu : ContentPage
    {
        public float totalprice { get; set; }
        public string json_response { get; set; }
        public string seletedMenu { get; set; }
        public string menuPrice { get; set; }
        public string quantity { get; set; }
        public string menucode { get; set; }


        public OrdernowMenu(PostSender posts1)
        {
            InitializeComponent();


            json_response = posts1.response;
            tester = posts1.teststring;
            GetUserAsync();
        }



        private async Task GetUserAsync()
        {

            var user = JsonConvert.DeserializeObject<List<Menus>>(json_response);

            MyOrder.ItemsSource = user;


        }



        public async Task MyOrder_ItemSelected(object sender, SelectedItemChangedEventArgs e)
        {

            var selectedOrder = e.SelectedItem as Menus;

            if (selectedOrder != null)

                seletedMenu = selectedOrder.menu_name;
            menuPrice = selectedOrder.menu_price;
            menucode = selectedOrder.menu_code;



            CartSender _sender = new CartSender()
            {
                nameofmenu = seletedMenu,
                priceofmenu = menuPrice,
                codeofmenu = menucode
            };

            var popup = new QuantityPopUp(_sender);
            await  Navigation.PushAsync(popup);

        }




        public void ToolbarItem_Clicked(object sender, EventArgs e)
        {



            Navigation.PushAsync(new OrderCart(null));


        }
    }

Step 2: This where you input the quantity of your order, and you tap OK it will be added to the orderlist/Cart

My Problem here: it only display my latest order in OrderCart.xaml and it doesn't stack if you have multiple orders.

image of QuantityPopUp.xaml

QuantityPopUp

Link:https://i.sstatic.net/cvlB4.jpg

QuantityPopUp.xaml

<ContentPage.ToolbarItems>
        <ToolbarItem Name="Cancel" Clicked="Cancel_Clicked" ></ToolbarItem>

    </ContentPage.ToolbarItems>
    <StackLayout Orientation="Vertical" VerticalOptions="Center">

        <StackLayout Orientation="Vertical" HorizontalOptions="Center">
            <Label Text="Input Quantity" FontAttributes="Bold" Font="30"/>
            <Entry x:Name="entQuantity" Placeholder="How many do you want?" Keyboard="Numeric" HorizontalTextAlignment="Center"/>
        </StackLayout>
        <StackLayout Orientation="Horizontal" VerticalOptions="Center" HorizontalOptions="Center">
            <Button x:Name="btnOK" Text="OK"  Clicked="btnOK_Clicked" />


        </StackLayout>
    </StackLayout>

QuantityPopUp.xaml.cs

public partial class QuantityPopUp : ContentPage
    {
        public string tempnameofmenu { get; set; }
        public string temppriceofmenu { get; set; }
        public string tempcodeofmenu { get; set; }
        public string tempquantityofmenu { get; set; }
        ObservableCollection<CartOrderAdd> test = new ObservableCollection<CartOrderAdd>();

        public QuantityPopUp (Data.CartSender _sender)
        {
            InitializeComponent();
            tempnameofmenu = _sender.nameofmenu;
            temppriceofmenu = _sender.priceofmenu;
            tempcodeofmenu = _sender.codeofmenu;

        }

        private void btnOK_Clicked(object sender, EventArgs e)
        {


            test.Add(new CartOrderAdd
            {
                nameofmenuCOA = tempnameofmenu,
                codeofmenuCOA = tempcodeofmenu,
                priceofmenuCOA = temppriceofmenu,
                quantityofmenuCOA = entQuantity.Text
            });


            var viewcart = new OrderCart(test);
            Navigation.PushAsync(viewcart);

        }



        private void Cancel_Clicked(object sender, EventArgs e)
        {
            Navigation.PushAsync(new OrdernowCategory());
        }
    }

Step 3: if you go to OrderCart.xaml this must display all of your orders.

My Problem Here: i don't know what's wrong because it only display a single order even though i have multiple orders.

image of OrderCart.xaml

OrderCart

Link:https://i.sstatic.net/qiiPP.jpg

OrderCart.xaml

 <ContentPage.ToolbarItems>
        <ToolbarItem Name="Back" Clicked="Back_Clicked" ></ToolbarItem>

    </ContentPage.ToolbarItems>

    <ListView x:Name="MyCart" ItemSelected="MyCart_ItemSelected"  RowHeight="50">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell >
                    <Grid>



                        <StackLayout Orientation="Horizontal">
                            <Label  Text="{Binding nameofmenuCOA}" Font="30" TextColor="Black" FontAttributes="Bold"/>
                            <Label  Text="{Binding priceofmenuCOA}" Font="30" TextColor="Black" FontAttributes="Bold"/>
                            <Label  Text="{Binding codeofmenuCOA}" Font="30" TextColor="Black" FontAttributes="Bold"/>
                            <Label  Text="{Binding quantityofmenuCOA}" Font="30" TextColor="Black" FontAttributes="Bold"/>
                        </StackLayout>


                    </Grid>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>

    </ListView>

OrderCart.xaml.cs

public partial class OrderCart : ContentPage
    {
        List<CartOrderAdd> _data;


        public OrderCart (System.Collections.ObjectModel.ObservableCollection<CartOrderAdd> test)
        {
            InitializeComponent ();


            MyCart.ItemsSource = test;
        }

        private void MyCart_ItemSelected(object sender, SelectedItemChangedEventArgs e)
        {

        }

        private void Back_Clicked(object sender, EventArgs e)
        {
            Navigation.PushAsync(new OrdernowCategory());
        }
    }

Upvotes: 0

Views: 1790

Answers (1)

Paul Kertscher
Paul Kertscher

Reputation: 9713

Your issue is quite simple, but occluded by the heaps of code you presented. The next time you should try to boil it down to a Minimal, Complete, and Verifiable example.

The test collection is an instance variable, that means that a new variable will be created of each instance of the containing class (QuantityPopUp). If I created multiple instances of the class

var a = new QuantityPopUp();
var b = new QuantityPopUp();
var c = new QuantityPopUp();

there would be three regions in memory, each containing a QuantityPopUp. And each of these would contain a pointer to a region im memory containing a ObservableCollection<CartOrderAdd> (alright, actually it's not quite that simple, but that will do as a simplified model to understand the issue). Each of the ObservableCollection<CartOrderAdd> might contain different values.

How does this relate to your issue?

Now whenever you click an item in your list, you are creating a new instance of type QuantityPopUp

var popup = new QuantityPopUp(_sender);

and hence a new instance of ObservableCollection<CartOrderAdd> is created, which is empty by default. You are immediately adding a meal to it and on clicking OK you are proceeding to your checkout cart. Even if there are other meals that should've been added to your cart, they are somewhere in memory in some lists, but (of course) not in your newly created list.

How can you solve this?

I'd suggest MVVM with dependency injection and a framework like Prism. You could create a Cart that gets injected in your viewmodels (please not that the added meals should either be persisted in memory or there should only be a single instance of Cart). The signature could look like the follwoing

class Cart
{
    public void AddOrder(string mealCode, int quantity);
    public IReadOnlyCollection<Meal> GetAddedMeals();
} 

Please note that only the mealCode and the quantity are passed, since it should not be up to the UI to determine the price (this would be redundant, error prone and potentially open the doors for abuses) and the name of the menu (not as crucial as the price, but still).

Now if you don't want/can't use MVVM with DI, you could make use of the Cart object. E.g. by passing it around between the views or by using a singleton implementation (I'd recommend neither, but you can).

The code behind of your views could look like the following.

public partial class QuantityPopUp : ContentPage
{
    // ...

    private void btnOK_Clicked(object sender, EventArgs e)
    {
        Cart.Instance.Add(tempcodeofmenu, int.Parse(entQuantity.Text));

        Navigation.PushAsync(new OrderCart());
    }

    // ...
}

public partial class OrderCart : ContentPage
{
    public OrderCart()
    {
        InitializeComponent ();

        MyCart.ItemsSource = Cart.Instance.GetAddedMeals();
    }

    // ...
}

Upvotes: 3

Related Questions