All docs
V20.2
21.1 (EAP/Beta)
20.2
20.1
19.2
The page you are viewing does not exist in version 19.2. This link will take you to the root page.
19.1
The page you are viewing does not exist in version 19.1. This link will take you to the root page.
18.2
The page you are viewing does not exist in version 18.2. This link will take you to the root page.
18.1
The page you are viewing does not exist in version 18.1. This link will take you to the root page.
17.2
The page you are viewing does not exist in version 17.2. This link will take you to the root page.

Create Object Data Source at Runtime

  • 8 minutes to read

Overview

The ObjectDataSource class instance serves as an intermediate layer to bind a report to a collection of data items.

The ObjectDataSource instance specifies the type, constructors, methods, and properties of a custom object that generates a collection of data items. A custom object can contain a method that populates the data item collection at runtime or retrieves the data from an external data source.

The ObjectDataSource is serialized in the report definition file (REPX). If you bind a report to a collection of custom objects, the data source information cannot be serialized and you cannot restore the data source when a report is loaded from the REPX file.

To bind a data item collection to a report, implement a custom object that populates the data item collection, create the ObjectDataSource for that object and assign the ObjectDataSource instance to the report's DataSource property.

NOTE

The complete sample project is available in the following DevExpress Examples repository on GitHub: How to Use the Object Data Source in Web Reporting Applications.

Create the Object Data Source

The following code creates a custom object (EmployeeList) that has a parameterized constructor, the Items property and the GetData method, which returns a collection of DataItem data objects:

Show EmployeeList
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
// ..
   [DisplayName("Employees")]
   public class EmployeeList
   {
       public EmployeeList()
       {
           Items = InitializeList();
       }
       public EmployeeList(int noOfItems)
       {

           Items = InitializeList().GetRange(1, noOfItems);
       }
       public List<DataItem> Items { get; set; }

       public List<DataItem> InitializeList()
       {
           return new List<DataItem>() {
               new DataItem(1, 101, "Andrew Fuller", "Dr.", "Vice President, Sales"),
               new DataItem(1, 102, "Anne Dodsworth", "Ms.", "Sales Representative"),
               new DataItem(1, 103, "Michael Suyama", "Mr.", "Sales Representative"),
               new DataItem(1, 104, "Janet Leverling", "Ms.", "Sales Representative"),
               new DataItem(1, 105, "Elliot Komaroff", "Dr.", "Sales Coordinator"),
               new DataItem(2, 201, "Nancy Davolio", "Ms.", "Sales Representative"),
               new DataItem(2, 202, "Steven Buchanan", "Mr.", "Sales Manager"),
               new DataItem(2, 203, "Laura Callahan", "Ms.", "Sales Coordinator"),
               new DataItem(3, 301, "Frédérique Citeaux", "Mr.", "Sales Coordinator"),
               new DataItem(3, 302, "Laurence Lebihan", "Mr.", "Sales Representative"),
               new DataItem(3, 303, "Elizabeth Lincoln", "Ms.", "Sales Manager"),
               new DataItem(3, 304, "Yang Wang", "Mr.", "Sales Representative"),
               new DataItem(4, 401, "Antonio Moreno", "Mr.", "Sales Representative"),
               new DataItem(4, 402, "Thomas Hardy", "Mr.", "Sales Representative"),
               new DataItem(4, 403, "Christina Berglund", "Ms.", "Sales Manager"),
               new DataItem(5, 501, "Alejandra Camino", "Ms.", "Sales Representative"),
               new DataItem(5, 502, "Matti Karttunen", "Mr.", "Sales Representative"),
               new DataItem(5, 503, "Rita Müller", "Mrs.", "Sales Representative"),
           };
       }

       public List<DataItem> GetData(int noOfItems)
       {
           List<DataItem> revertList = new List<DataItem>(Items);
           revertList.Reverse();
           return revertList.Take(noOfItems).ToList();
       }
   }
   public class DataItem
   {
       public DataItem(int floor, int office, string personName, string titleOfCourtesy, string title)
       {
           Floor = floor;
           Office = office;
           PersonName = personName;
           TitleOfCourtesy = titleOfCourtesy;
           Title = title;
       }
       public int Floor { get; set; }
       public int Office { get; set; }
       public string PersonName { get; set; }
       public string TitleOfCourtesy { get; set; }
       public string Title { get; set; }
   }

You can create an object data source that is bound to a parameterized object constructor or the object data source that uses the GetData method.

Bind to the Parameterized Object Constructor

The following code creates an object data source that is bound to the Items property and uses the ObjectDataSource.Constructor property to pass the value to the EmployeeList constructor:

using DevExpress.DataAccess.ObjectBinding;
// ...
    private object CreateObjectDataSource()
    {
        ObjectDataSource dataSource = new ObjectDataSource();
        dataSource.Name = "EmployeeObjectDS";
        dataSource.DataSource = typeof(Employees.EmployeeList);
        // Specify the parameter's default value.
        var parameter = new Parameter("noOfItems", typeof(int), 7);
        dataSource.Constructor = new ObjectConstructorInfo(parameter);
        dataSource.DataMember = "Items";
        return dataSource;
    }

Bind to a Method

The following code creates an object data source that is bound to the GetData method. The method accepts an argument of the number of items to retrieve.

using DevExpress.DataAccess.ObjectBinding;
// ...
    private object CreateObjectDataSource()
    {
        ObjectDataSource dataSource = new ObjectDataSource();
        dataSource.Name = "EmployeeObjectDS";
        dataSource.DataSource = typeof(Employees.EmployeeList);
        var parameterNoOfItems = new Parameter("noOfItems", typeof(int), 12);
        dataSource.Parameters.Add(parameterNoOfItems);
        dataSource.DataMember = "GetData";
        dataSource.Constructor = ObjectConstructorInfo.Default;
        return dataSource;
    }

Map the Report Parameter to the Data Source Parameter

The following code creates an object data source with a parameter that is bound to the report's parameterNoOfItems parameter. Users can change the report's parameter and filter the data retrieved from the data source.

using DevExpress.DataAccess.ObjectBinding;
// ...
    private object CreateObjectDataSource()
    {
        ObjectDataSource dataSource = new ObjectDataSource();
        dataSource.Name = "EmployeeObjectDS";
        dataSource.DataSource = typeof(Employees.EmployeeList);
        // Map data source parameter to report's parameter.
        var parameter = new Parameter()
        {
            Name = "noOfItems",
            Type = typeof(DevExpress.DataAccess.Expression),
            Value = new DevExpress.DataAccess.Expression("?parameterNoOfItems", typeof(int))
        };
        dataSource.Constructor = new ObjectConstructorInfo(parameter);
        dataSource.DataMember = "Items";
        return dataSource;
    }

Recreate the Data Source for the Loaded Report

The report definition file (REPX file) contains the following ObjectDataSource information: the type of an object used for the object data source, the object's property or method name used to retrieve data, and the parameters. This information is Base-64 encoded.

When the Document Viewer loads a report, it attempts to recreate the data source and use it to retrieve data. If the object that serves as the data source is not defined or referenced in your project, an attempt to recreate the data source fails. In this situation, you can implement a custom IWebDocumentViewerReportResolver service that assigns a data source to the report before the Document Viewer displays it.

The IWebDocumentViewerReportResolver service receives the report's name passed to the Document Viewer and uses it to create a report and an object data source, bind the report to the data source, and return the report to the Document Viewer. The service can use the methods described in the previous section to create the object data source.

You should register the service at application startup:

// ...
    public class Startup {
        // ...
        public void ConfigureServices(IServiceCollection services) {
            // ...
            services.AddTransient<IWebDocumentViewerReportResolver, CustomWebDocumentViewerReportResolver>();
            // ../            
        }
        // ...
    }
See Also