Search code examples
c#linqdevexpressxtrareport

Devexpress dynamic creating ExtraReports and dynamic binding to object as a datasource


I have three classes(Employee, EmployeeCard, and Children) implemented like this

public class Employee
{
   public Employee()
   {
       Children = new List<Child>();
   }
   public virtual string FirstName { get; set; }
   public virtual string LastName { get; set; }
   public virtual EmployeeCard EmployeeCard { get; set; }
   public virtual IList<Child> Children { get; protected set; }
   public virtual void AddChild(Child child)
   {
       child.Employee = this;
       Children.Add(child);
   }
   public static List<Employee> GetData()
   {
       List<Employee> empList = new List<Employee>();
       for(i=0;i<5;i++)
       {
           Employee emp = new Employee();
           emp.FirstName = "Fname" + i.ToString();
           emp.LastName = "Lname" + i.ToString();
           emp.EmployeeCard = new EmployeeCard();
           emp.EmployeeCard.StartWorkingDate = DateTime.Now.Date.AddDays(-i);
           empList.Add(emp);
            for(int j=0;j<2;j++)
            {
                Children child = new Children();
                child.FirstName = "ChildFname" + j.ToString();
                child.LastName = "ChildLname" + j.ToString();
                empList.Children.Add(child);
            }
       }
       return empList;
   }
}

public class Child
{
   public virtual string FirstName { get; set; }
   public virtual string LastName { get; set; }
   public virtual Employee Employee { get; set; }  
}

public class EmployeeCard
{
   public virtual Employee Employee { get; set; }
   public virtual DateTime? StartWorkingDate { get; set; }
}

when I bind list of employees to a report at run time I got this error

cannot bind to the provided datasource because it's not supported or not implemented in our supported interfaces.

and when I remove the reference employee card from the employee class It works perfectly. how can I bind the details of employeecard to the report using list of employees??

here is the sample code of how I created the xtraReports

update 1

this is how I build the employee objects and binding them to the report

XtraReport report = new XtraReport();
        List<Employee> ReportDataSource = Employee.GetData();
        ReportHeaderBand headerBand = new ReportHeaderBand() {
            HeightF = 80
        };
        report.Bands.Add(headerBand);

        headerBand.Controls.Add(new XRLabel() {
            Text = "Employee Report",
            SizeF = new SizeF(650, 80),
            TextAlignment = TextAlignment.BottomCenter,
            Font = new Font("Arial", 36)
        });


        DetailBand detailBandEmployee = new DetailBand();
        var detailReportBandEmployee = new DetailReportBand
        {
            KeepTogether = true,
            DataMember ="",
            DataSource = ReportDataSource
        };
        detailReportBandEmployee.Bands.Add(detailBandEmployee);



        XRLabel lbFname = new XRLabel() {
            LocationF = new PointF(200, 10),
            SizeF = new SizeF(440, 50),
            TextAlignment = TextAlignment.BottomLeft,
            Font = new Font("Arial", 24)
        };
        detailBandEmployee.Controls.Add(lbFname);
        lbFname.DataBindings.Add("Text", null, "FirstName");

        XRLabel lbLastName = new XRLabel() {
            LocationF = new PointF(200, 60),
            SizeF = new SizeF(440, 40),
            TextAlignment = TextAlignment.TopLeft,
            Font = new Font("Arial", 14, FontStyle.Italic)
        };
        detailBandEmployee.Controls.Add(lbLastName);
        lbLastName.DataBindings.Add("Text", null, "LastName");
        DetailBand detailBandEmployeeChild = new DetailBand();
        var detailReportBandEmployeeChild = new DetailReportBand
        {
            KeepTogether = true,
            DataMember = "Children",
            DataSource = ReportDataSource
        };
        detailReportBandEmployeeChild.Bands.Add(detailBandEmployeeChild);



        XRLabel lbChildFname = new XRLabel()
        {
            LocationF = new PointF(200, 10),
            SizeF = new SizeF(440, 50),
            TextAlignment = TextAlignment.BottomLeft,
            Font = new Font("Arial", 24)
        };
        detailBandEmployeeChild.Controls.Add(lbChildFname);
        lbChildFname.DataBindings.Add("Text", null, "FirstName");

        XRLabel lbChildLastName = new XRLabel()
        {
            LocationF = new PointF(200, 60),
            SizeF = new SizeF(440, 40),
            TextAlignment = TextAlignment.TopLeft,
            Font = new Font("Arial", 14, FontStyle.Italic)
        };
        detailBandEmployeeChild.Controls.Add(lbChildLastName);
        lbChildLastName.DataBindings.Add("Text", null, "LastName");
        DetailBand detailBandEmployeeCard = new DetailBand();
        var detailReportBandEmployeeCard = new DetailReportBand
        {
            KeepTogether = true,
            DataMember = "EmployeeCard  ",
            DataSource = ReportDataSource
        };
        detailReportBandEmployeeCard.Bands.Add(detailBandEmployeeCard);



        XRLabel lbStartDate = new XRLabel()
        {
            LocationF = new PointF(200, 10),
            SizeF = new SizeF(440, 50),
            TextAlignment = TextAlignment.BottomLeft,
            Font = new Font("Arial", 24)
        };
        detailBandEmployeeCard.Controls.Add(lbStartDate);
        lbStartDate.DataBindings.Add("Text", null, "StartWorkingDate");

        detailReportBandEmployee.Bands.Add(detailReportBandEmployeeCard);
        detailReportBandEmployee.Bands.Add(detailReportBandEmployeeChild);
        report.Bands.Add(detailReportBandEmployee);

Solution

  • The problem is that you created the detail band for the card like this

    var detailReportBandEmployeeCard = new DetailReportBand
    {
         KeepTogether = true,
         DataMember = "EmployeeCard",
         DataSource = ReportDataSource
    };
    

    And that binds the datasource to this property

    public virtual EmployeeCard EmployeeCard { get; set; }
    

    You can only use lists as datasource and EmployeCard is not a list. If you only have a single object you don't need the detailBandEmployeeCard and you can put your labels directly into detailBandEmployee

    XRLabel lbStartDate = new XRLabel()
    {
        LocationF = new PointF(200, 10),
        SizeF = new SizeF(440, 50),
        TextAlignment = TextAlignment.BottomLeft,
        Font = new Font("Arial", 24)
    };
    //detailBandEmployeeCard.Controls.Add(lbStartDate);
    //lbStartDate.DataBindings.Add("Text", null, "StartWorkingDate");
    
    detailBandEmployee.Controls.Add(lbLastName);
    lbStartDate.DataBindings.Add("Text", null, "EmployeeCard.StartWorkingDate");
    

    GetData() use a class Children when it should be Child, also it don't populate the list. I think the loop must be something like this

    for (int j = 0; j < 2; j++)
    {
         Child child = new Child();
         child.FirstName = "ChildFname" + j.ToString();
         child.LastName = "ChildLname" + j.ToString();
         emp.AddChild(child);
    }