Search code examples
wpfmvvmdata-bindingmultibinding

How do you set your ItemsControl ItemsSource to see a collection of objects and also the collection of child-objects within one of the parent-objects


Basically what I have is an ItemsControl and I have set the ItemsSource="{Binding =Invoice.Jobs". Within that Jobs collection I have two other collections called "Shipments" and "Fees". I have it set up so that the ItemsControl.Resources is filled with DataTemplates that determine the type of CustomControl I will use for each Job, Shipment, or Fee. They determine this by the DataType of each of those. So the ItemsControl is supposed to pump out all of those controls one after another to kind of look like Line Items in an invoice. One group of Line items would be: -Job -Shipment -Fee

Then if there were more jobs or of the others it could look like -Job -Shipment -Shipment -Fee -Job -Shipment

<ItemsControl ItemsSource="{Binding Invoice.Jobs}">
    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type preInvoice:BatchInvoiceJobDto }">
            <control:JobLineItem>
            </control:JobLineItem>
        </DataTemplate>
        <DataTemplate DataType="{x:Type preInvoice:BatchInvoiceShipmentDto}">
            <control:ShipmentLineItem>
            </control:ShipmentLineItem>
        </DataTemplate>
        <DataTemplate DataType="{x:Type preInvoice:BatchInvoiceFeeDto }">
            <control:FeeLineItem>
            </control:FeeLineItem>
        </DataTemplate>
    </ItemsControl.Resources>
</ItemsControl>

The Jobs class basically looks like this:

public class Invoice
{
    public IEnumerable<BatchInvoiceJobDto> Jobs {get; set;}
}

public class BatchInvoiceJobDto
{
    public IEnumerable<BatchInvoiceShipmentDto> Shipments {get; set;}
    public IEnumerable<BatchInvoiceFeeDto> Fees{get; set;}
}

Solution

  • In order to traverse the Collections within your Invoice.Jobs Collection I would suggest nested ItemsControl controls.

    XAML:

     <ItemsControl ItemsSource="{Binding Invoice.Jobs}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel>
    
                    <ItemsControl ItemsSource="{Binding Shipments}">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
    
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
    
                    <ItemsControl ItemsSource="{Binding Fees}">
                         <ItemsControl.ItemTemplate>
                             <DataTemplate>
    
                             </DataTemplate>
                         </ItemsControl.ItemTemplate>
                    </ItemsControl>
    
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    If you were to set the ItemsControl.ItemsPanel to a StackPanel for each ItemsControl then it should display as rows following the Job -> Shipments -> Fees order for each item in Invoice.Jobs.

    Note:

    You may want to change your property types from IEnumerable to ObservableCollection so that they will update and display correctly.