allyouneedisdave
allyouneedisdave

Reputation: 39

How can I display a list of objects within a list of objects, with a multi value header

I am trying to display a list of objects that contain a list of objects. I have gone down a few rabbit holes, including grouping ObservableCollections but haven't been able to implement the right approach. From what I can tell, grouping only uses a single title/key (can anyone confirm this?).

For context, I am making a barcode scanning Android app for vehicle loading using Xamarin Forms and C#.

I have an object for a Shipping Order, which is the parent item, with the labels Order Ref, Cust Name and Delivery Date.

Within this object there are multiple Shipping Items, listed Item 1, Item 2 etc.

I have mocked up a rough example of how I would like the data to be structured in the view. I want to be able to bind all of these entries, so background colours can be changed when the items are scanned, and the parent colour changed when all items for the order have been fulfilled.

I'd be grateful if you could point me in the right direction.

UI Mock Up

--Edit-- Thanks for the guidance, I seem to be going round in circles with Grouping, though i'm clearly missing something. I can get a test case working, following tutorials with simple data but I'm struggling to adapt it to my models. I've added a simplified version of them below, would grouping work with these models or do I need to change the way i'm thinking about this??

ShippingOrder Model

    public class ShippingOrder
{
    public int Id { get; set; }
    public string OrderRef { get; set; }
    public string CustName { get; set; }
    public DateTime DeliveryDate { get; set; }
    public ObservableCollection<ShippingItem> ShippingItems { 
get; set; }
}

ShippingItem Model

public class ShippingItem
{
    public int Id { get; set; }
    public int ShippingOrderId { get; set; }
    public string ItemDescription { get; set; }
    public bool IsLoaded { get; set; }
}

Shipment Model

public class Shipment
   

 {
        public int ShipmentId { get; set; }
        public string VehicleId { get; set; }
        public DateTime DepartureDate { get; set; }
        public ObservableCollection<ShippingOrder> ShippingOrders 
{ get; set; }

        public Shipment()
        {
            // Generate mock data.
            ShipmentId = 1;
            VehicleId = "Trailer 3";
            DepartureDate = DateTime.Parse("05/08/2022");
            ShippingOrders = new 
ObservableCollection<ShippingOrder> ();

            //Order 1
            ShippingOrder shippingOrder1 = new ShippingOrder();
            shippingOrder1.Id = 1;
            shippingOrder1.OrderRef = "001";
            shippingOrder1.CustName = "John Smith";
            shippingOrder1.DeliveryDate = 
DateTime.Parse("06/08/2022");

            shippingOrder1.ShippingItems = new 
ObservableCollection<ShippingItem>();
            shippingOrder1.ShippingItems.Add(new ShippingItem {Id 
= 1, ShippingOrderId = 1, IsLoaded = false, ItemDescription = 
"Large Box" });
            shippingOrder1.ShippingItems.Add(new ShippingItem { 
Id = 2, ShippingOrderId = 1, IsLoaded = false, ItemDescription = 
"Medium Box" });
ShippingOrders.Add(shippingOrder1);


            //Order 2
            ShippingOrder shippingOrder2 = new ShippingOrder();
            shippingOrder2.Id = 2;
            shippingOrder2.OrderRef = "002";
            shippingOrder2.CustName = "Dwayne Dibley";
            shippingOrder2.DeliveryDate = 
DateTime.Parse("06/08/2022");

            shippingOrder2.ShippingItems = new 
ObservableCollection<ShippingItem>();
            shippingOrder2.ShippingItems.Add(new ShippingItem { 
Id = 3, ShippingOrderId = 2, IsLoaded = false, ItemDescription = 
"Small Box" });
            shippingOrder2.ShippingItems.Add(new ShippingItem { 
Id = 4, ShippingOrderId = 2, IsLoaded = false, ItemDescription = 
"Small Box" });
            shippingOrder2.ShippingItems.Add(new ShippingItem { 
Id = 5, ShippingOrderId = 2, IsLoaded = false, ItemDescription = 
"Medium Envelope" });
ShippingOrders.Add(shippingOrder2);


            // Order 3
            ShippingOrder shippingOrder3 = new ShippingOrder();
            shippingOrder3.Id = 3;
            shippingOrder3.OrderRef = "003";
            shippingOrder3.CustName = "Paul Ramone";
            shippingOrder3.DeliveryDate = 
DateTime.Parse("06/08/2022");
            shippingOrder3.ShippingItems = new 
ObservableCollection<ShippingItem>();
            shippingOrder3.ShippingItems.Add(new ShippingItem { 
Id = 6, ShippingOrderId = 3, IsLoaded = false, ItemDescription = 
"Large Box" });
            shippingOrder3.ShippingItems.Add(new ShippingItem { 
Id = 8, ShippingOrderId = 3, IsLoaded = false, ItemDescription = 
"Small Box" });

ShippingOrders.Add(shippingOrder3);

        }
    }

Upvotes: 1

Views: 283

Answers (1)

Andrew
Andrew

Reputation: 1438

No reason to overcomplicate it too bad.

You need to create a grouping class to hold your items:

public class ShippingItemGroup : ObservableCollection<ShippingItem>
{
    public ShippingOrder Shipment { get; private set; }

    public ShippingItemGroup(ShippingOrder shipment, ObservableCollection<ShippingItem> shippingItems) : base(shippingItems)
    {
        Shipment = shipment;
    }
}

In your view model or page, set up your ObservableCollection and add your items to it:

public MainPage()
{
    InitializeComponent();

    var shipment = new Shipment();

    foreach (var item in shipment.ShippingOrders)
    {
        ShippingItems.Add(new ShippingItemGroup(item, item.ShippingItems));
    }

    BindingContext = this;
}

public ObservableCollection<ShippingItemGroup> ShippingItems { get; private set; } = new ObservableCollection<ShippingItemGroup>();

Finally setup your CollectionView:

<CollectionView IsGrouped="True" ItemsSource="{Binding ShippingItems}">
    <CollectionView.GroupHeaderTemplate>
        <DataTemplate>
            <StackLayout Orientation="Horizontal" BackgroundColor="LightBlue" HeightRequest="45">
                <Label Text="{Binding Shipment.OrderRef}" VerticalOptions="Center"/>
                <Label Text="{Binding Shipment.CustName}" VerticalOptions="Center"/>
                <Label Text="{Binding Shipment.DeliveryDate}" HorizontalOptions="EndAndExpand" VerticalOptions="Center" />
            </StackLayout>                    
        </DataTemplate>
    </CollectionView.GroupHeaderTemplate>
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Label Text="{Binding ItemDescription}" />
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

Running Result:

enter image description here

Style as desired.

Upvotes: 1

Related Questions