Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Grouped Carousel / CollectionView

I have an application that has a list of products... The product Class contains a PRICE... I am attempting to use a :tabbed navigation page with left /right tab navigation disabled... Now, what I would like is to have a "Grouped Carousel" that navigates PRICE horizontally... and gives me a CardView stacked list Vertically for each price target... There are approximately 7 to 10 price targets...

$5.00 ==> $10.00 <==> $ 20.00 <==> $30.00

The each view would have a cardlist of the items that fall into that Price Target?

I have attempted using the CollectionView with Grouped but that was a mess... Once it is compiled the application continues to cache the grouped price list... The solution needs to cleaned and the OBJ and BIN folders need to be removed manually... The View and ViewModel need to be removed and the app needs to be recompiled without them...

Solutions?

Best Answer

  • StewartBasterashStewartBasterash USMember ✭✭
    Accepted Answer

    I will look at your code... Thank you again for your quick help...

    I may have been overthinking the problem... Back in the day, we used to derive custom controls from others... Much like using custom controls in Java... I was able to create two bindable properties... Text and IsChecked... I then packaged three controls inside a grid... A Frame, a Label, and a Checkbox... I then used Triggers to completely make the checkbox the "controller" within the control... The triggers change the look of the Label and Frame only, while color and background color of the checkbox are both "Transparent"... This works exactly like I wanted it to...

    Thanks again.

Answers

  • JarvanJarvan Member, Xamarin Team Xamurai
    edited June 5

    I have attempted using the CollectionView with Grouped but that was a mess...

    You could create a global static ObservableCollection property in App class, then set binding data to each child page of the CarouselPage with the property. All the products data are from the same collection object, it'll easy to handle the data.

    App.xaml.cs

    public partial class App : Application
    {
        public static ObservableCollection<GoodsViewModel> viewModel;
        public App()
        {
            InitializeComponent();
    
            viewModel = new ObservableCollection<GoodsViewModel>();
            InitializeData();
    
            MainPage = new NavigationPage(new CarouselPage1());
        }
    
        private void InitializeData()
        {
            viewModel.Add(new GoodsViewModel
            {
                Price = 5,
                Products = new ObservableCollection<Products>()
                    {
                        new Products{ Item_Name = "Product_1_1"},
                        new Products{ Item_Name = "Product_1_2"},
                        new Products{ Item_Name = "Product_1_3"}
                    }
            });
            ...
        }
    }
    

    CarouselPage.xaml

    <CarouselPage
        ...
        xmlns:local="clr-namespace:App19F_5"
        x:Class="App19F_5.CarouselPage1">
    
        <local:Page1 />
        <local:Page2 />
        <local:Page3 />
    
    </CarouselPage>
    

    Page.xaml.cs

    public partial class Page1 : ContentPage
    {
        public Page1()
        {
            InitializeComponent();
    
            BindingContext = App.viewModel[0];
        }
    }
    

    Model class and ViewModel class

    public class Products : INotifyPropertyChanged
    {
        private string item_name;
        public string Item_Name
        {
            get
            {
                return item_name;
            }
            set
            {
                if (item_name != value)
                {
                    item_name = value;
                    NotifyPropertyChanged("Item_Name");
                }
            }
        }
    
        protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    }
    
    public class GoodsViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<Products> Products { get; set; } = new ObservableCollection<Products>();
    
        private double price;
        public double Price
        {
            get
            {
                return price;
            }
            set
            {
                if (price != value)
                {
                    price = value;
                    NotifyPropertyChanged("Price");
                }
            }
        }
        protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    }
    

  • StewartBasterashStewartBasterash USMember ✭✭

    @Jarvan

    Thanks for the information. This was helpful. I found that my problem has nothing to do with how I was coding the page, it is the deployment to the Android VM... Xamarin is NOT very friendly when it comes to updating and changing code... Cleaning a solution, rebuilding, and running on vm are not intuitive and problematic. I get errors on code that has been removed from within the VM debug session.

    At this point I have the code working, but commanding is NOT working and I'm not sure why... I've created a new List where Product Price is a Class { double price, List items }. This allowed me to set the carousel itemsource... Now, when I slide the carousel it displays all the products in the price category... I have attached a Tap Command on the Image of each produce to "Product Detail view"... Currently, my viewmodel contains the Tap ICommand required, but the code is never called, and debug emulator is telling me that the "MyCommand" is not found. I may have to use the Path parameter or something to find the image detail, but with the compile and run issues with Xamarin it is kind of a crap shoot! This is frustrating!

  • JarvanJarvan Member, Xamarin Team Xamurai
    edited June 6

    but the code is never called, and debug emulator is telling me that the "MyCommand" is not found.

    Please post the related code, it'll help to get the cause.

  • StewartBasterashStewartBasterash USMember ✭✭

    In terms of code... the code snippet that you provided is 95% exactly what i have... The behavior I am looking for is to have
    a "Tap Gesture" event for each of the "products"... This in turn would bring up a view with FULL Product Detail. I am using an MVVM construct and attempted to add a command and commandparameter so I could make the call to an event within the ViewModel class... I receive a error within the VM debugger telling me that the method call cannot be found. I currently have overcome the issue by placing a "click" event into the "code behind" for the XAML (an MVVM no-no). I am using the image name as the passed parameter, as I have named the images by "productid.png". I would prefer to keep the MVVM seperation if I can make this work...

    This is psuedo code in ProduceViewModel.cs...

        public ICommand ShowDetail
        {
            get
            {
                return new Command<string>((x) => executeDetailView(x));
            }
        }
        public void executeDetailView(string productid)
        {
            Console.WriteLine(productid);
            //using linq to find full product by productid => executeview(productid); 
        }
    

    This is bound in XAML with:

    current:
    <Image.GestureRecognizers>

    </Image.GestureRecognizers>

    mvvm: (this gives error in vm debugger... ShowDetail cannot be found in WI2020.View.ProductView )

    <Image.GestureRecognizers>

    </Image.GestureRecognizers>

    My code structure in Xamarin is:




    I hope this helps?

  • JarvanJarvan Member, Xamarin Team Xamurai

    I am looking for is to have a "Tap Gesture" event for each of the "products"

    If you want to add the tap gesture for the product items, the command should be added in the 'Product' class instead of the ViewModel class.

  • StewartBasterashStewartBasterash USMember ✭✭

    Well... That is one I missed... I was going to do some additional reading to understand the command syntax. I would have thought that the event would occur as part of the UI not the Model...

    Thank you for the clarification, I will test this! :smile:

  • StewartBasterashStewartBasterash USMember ✭✭
    edited June 7

    @Jarvan

    So, I got this to work with an ICommand and a CommandParameter... The problem is, the code, as you suggested, had to be in the model.cs file... Curious.. this does not help at all, and in fact makes no sense to me. In addition, it caused other issues...

    My project is structured in a purely MVVM way: From the root I have folders for Model, View, ViewModel...

    1. I have Product.cs in the Model folder... This is a typical C# model class...
    2. I have ProductViewModel.cs in the ViewModel folder... This has all the VM stuff, including INotifyPropertyChanged.
    3. I have a View called Products... This of course includes the "code behind CS file".
    4. Based on examples and our conversation I have a NEW model class called PriceProducts.
      public class PriceProduct()
      public double Price {get; set;}
      public List Items {get; set;}

    Now... I have a Products ContentPage, and a ProductDetail Content Page...
    The BindingContext of the Products View is... new ProductViewModel(); In this ViewModel I instantiate the ProductList, which is, with real data, a List. This has 7 price targets, and my Carousel View swipes through these 7 items... For each Price I have a list of products that are in that price target. I have a FlexLayout that shows "CardView"s of each product. The TapGesture should launch a Detail Page of the product...

        XAML
        <Image Source="{Binding localimage}" Aspect="AspectFill" >
            <Image.GestureRecognizers>
                    <TapGestureRecognizer Tapped="OnButtonClicked" NumberOfTapsRequired="1" />
                            <!--Tapped="OnButtonClicked" NumberOfTapsRequired="1" />-->
                               <!--Command="{Binding ShowDetail}" CommandParameter="{Binding name}"-->
                               </Image.GestureRecognizers>
                                                                        <Image.Triggers>
                                                                            <DataTrigger TargetType="Image" Binding="{Binding remaining}" Value="0">
                                                                                <Setter Property="Opacity" Value="0.5" />
                                                                            </DataTrigger>
                                                                        </Image.Triggers>
                                                                    </Image>
    
        Code Behind... 
            private void OnButtonClicked(object sender, EventArgs e)
                    {
                        var itemname = Path.GetFileNameWithoutExtension((sender as Image).Source.ToString());
                        (BindingContext as ProductsViewModel).SelectedItem = (BindingContext as ProductsViewModel).FullProductList.Where(i => i.productid == int.Parse(itemname)).FirstOrDefault();
                        Navigation.PushAsync(new ProductsDetail((BindingContext as ProductsViewModel).SelectedItem));
                    }
    

    This code currently works in the code behind because I have access to the Binding context of the view, the product, and because I used the productid.png for the image, the Sender in the code behind is the image that was tapped... With an MVVM approach that pushes everything back to the Product.cs model... and only being able to pass a string as a parameter, I really can't see a way forward with that methodology... although I'm sort of new at this... so...

  • JarvanJarvan Member, Xamarin Team Xamurai

    The code works fine on my side, I shared the demo file. You could test it on your side.

  • StewartBasterashStewartBasterash USMember ✭✭
    Accepted Answer

    I will look at your code... Thank you again for your quick help...

    I may have been overthinking the problem... Back in the day, we used to derive custom controls from others... Much like using custom controls in Java... I was able to create two bindable properties... Text and IsChecked... I then packaged three controls inside a grid... A Frame, a Label, and a Checkbox... I then used Triggers to completely make the checkbox the "controller" within the control... The triggers change the look of the Label and Frame only, while color and background color of the checkbox are both "Transparent"... This works exactly like I wanted it to...

    Thanks again.

Sign In or Register to comment.