Skip to main content

DevExpress v24.2 Update — Your Feedback Matters

Our What's New in v24.2 webpage includes product-specific surveys. Your response to our survey questions will help us measure product satisfaction for features released in this major update and help us refine our plans for our next major release.

Take the survey Not interested

Bind a Report to a Collection that Implements the ITypedList Interface (Runtime Sample)

  • 7 minutes to read

This tutorial demonstrates how to create a hierarchical master-detail data source at runtime and bind a report to it.

#Implement the ITypedList Interface to Data Objects

If a report’s data source consists of objects created at runtime, it should implement the ITypedList interface. The code below demonstrates how to implement the ITypedList interface for a 3-tier Supplier-Product-OrderDetail hierarchical data source.

using System;
using System.Collections;
using System.ComponentModel;
// ...

public class SupplierCollection : ArrayList, ITypedList {
    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) {
        if (listAccessors != null && listAccessors.Length > 0) {
            PropertyDescriptor listAccessor = listAccessors[listAccessors.Length - 1];
            if (listAccessor.PropertyType.Equals(typeof(ProductCollection)))
                return TypeDescriptor.GetProperties(typeof(Product));
            else if (listAccessor.PropertyType.Equals(typeof(OrderDetailCollection)))
                return TypeDescriptor.GetProperties(typeof(OrderDetail));
        }
        return TypeDescriptor.GetProperties(typeof(Supplier));
    }
    string ITypedList.GetListName(PropertyDescriptor[] listAccessors) {
        return "Suppliers";
    }
}

public class Supplier {
    static int nextID = 0;
    int id;
    string name;
    ProductCollection products = new ProductCollection();

    public ProductCollection Products { get { return products; } }
    public int SupplierID { get { return id; } }
    public string CompanyName { get { return name; } }

    public Supplier(string name) {
        this.name = name;

        this.id = nextID;
        nextID++;
    }
    public void Add(Product product) {
        products.Add(product);
    }
}

public class ProductCollection : ArrayList, ITypedList {
    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) {
        return TypeDescriptor.GetProperties(typeof(Product));
    }
    string ITypedList.GetListName(PropertyDescriptor[] listAccessors) {
        return "Products";
    }
}

public class Product {
    static int nextID = 0;

    OrderDetailCollection orderDetails = new OrderDetailCollection();
    int suppID;
    int prodID;
    string name;

    public int SupplierID { get { return suppID; } }
    public int ProductID { get { return prodID; } }
    public string ProductName { get { return name; } }
    public OrderDetailCollection OrderDetails { get { return orderDetails; } }

    public Product(int suppID, string name) {
        this.suppID = suppID;
        this.name = name;

        this.prodID = nextID;
        nextID++;
    }
}

public class OrderDetailCollection : ArrayList, ITypedList {
    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) {
        return TypeDescriptor.GetProperties(typeof(OrderDetail));
    }
    string ITypedList.GetListName(PropertyDescriptor[] listAccessors) {
        return "OrderDetails";
    }
}

public class OrderDetail {
    int prodID;
    short quantity;
    public int ProductID { get { return prodID; } }
    public short Quantity { get { return quantity; } }

    public OrderDetail(int prodID, int quantity) {
        this.prodID = prodID;
        this.quantity = Convert.ToInt16(quantity);
    }
}

#Create Data

The following code demonstrates how to create the data objects declared in the previous section and populate them with data:

private SupplierCollection CreateData() {
    SupplierCollection suppliers = new SupplierCollection();

    Supplier supplier = new Supplier("Exotic Liquids");
    suppliers.Add(supplier);
    supplier.Add(CreateProduct(supplier.SupplierID, "Chai"));
    supplier.Add(CreateProduct(supplier.SupplierID, "Chang"));
    supplier.Add(CreateProduct(supplier.SupplierID, "Aniseed Syrup"));

    supplier = new Supplier("New Orleans Cajun Delights");
    suppliers.Add(supplier);
    supplier.Add(CreateProduct(supplier.SupplierID, "Chef Anton's Cajun Seasoning"));
    supplier.Add(CreateProduct(supplier.SupplierID, "Chef Anton's Gumbo Mix"));

    supplier = new Supplier("Grandma Kelly's Homestead");
    suppliers.Add(supplier);
    supplier.Add(CreateProduct(supplier.SupplierID, "Grandma's Boysenberry Spread"));
    supplier.Add(CreateProduct(supplier.SupplierID, "Uncle Bob's Organic Dried Pears"));
    supplier.Add(CreateProduct(supplier.SupplierID, "Northwoods Cranberry Sauce"));

    return suppliers;
}

static Random random = new Random(5);

private Product CreateProduct(int supplierID, string productName) {
    Product product = new Product(supplierID, productName);

    product.OrderDetails.AddRange(new OrderDetail[] { 
        new OrderDetail(product.ProductID, random.Next(0, 100)), 
        new OrderDetail(product.ProductID, random.Next(0, 100)),
        new OrderDetail(product.ProductID, random.Next(0, 100)) });

    return product;
}

#Create a Report

The following code demonstrates how to create a 3-tier master-detail report at runtime, add bands and controls to it, and bind the report to an ITypedList data source that was created in the previous sections.

using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Configuration;
// ...

private XtraReport CreateReport() {
    XtraReport report = new XtraReport();

    DetailBand detail = new DetailBand();
    detail.Height = 30;
    report.Bands.Add(detail);

    DetailReportBand detailReport1 = new DetailReportBand();
    report.Bands.Add(detailReport1);

    DetailBand detail1 = new DetailBand();
    detail1.Height = 30;
    detailReport1.Bands.Add(detail1);

    DetailReportBand detailReport2 = new DetailReportBand();
    detailReport1.Bands.Add(detailReport2);

    DetailBand detail2 = new DetailBand();
    detail2.Height = 30;
    detailReport2.Bands.Add(detail2);

    report.DataSource = CreateData();
    detailReport1.DataMember = "Products";
    detailReport2.DataMember = "Products.OrderDetails";

    detail.Controls.Add(CreateBoundLabel("CompanyName", Color.Gold, 0));
    detail1.Controls.Add(CreateBoundLabel("Products.ProductName", Color.Aqua, 100));
    detail2.Controls.Add(CreateBoundLabel("Products.OrderDetails.Quantity", Color.Pink, 200));

    return report;
}

private XRLabel CreateBoundLabel(string dataMember, Color backColor, int offset) {
    XRLabel label = new XRLabel();
    // Bind the label to data.
    label.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Text", dataMember));
    label.BackColor = backColor;
    label.Location = new Point(offset, 0);

    return label;
}

#View the Result

The following code creates a report and shows its preview:

private void button1_Click(object sender, EventArgs e) {
    XtraReport report = CreateReport();

    // Show the report's print preview.
    ReportPrintTool printTool = new ReportPrintTool(report);
    printTool.ShowPreview();
}

The resulting report is shown in the image below.

HowTo_ITypedList1

See Also