0

I'm trying to create a library for creating reports in WPF from observable collections, but I can't figure out how to loop over ObservableCollection to write values into FlowDocument table. I tried with casting generic collection to an IEnumerable, but I keep getting

Exception thrown: 'System.NullReferenceException'

goal is to write a library which will accept all ObservableCollection types, so I've written this class (snippet):

public class Report_Definition<T> : INotifyPropertyChanged
{
        public Report_Definition(FlowDocument doc, ObservableCollection<T> data)
        {
            Fill_data(data, doc);
        }

        private void Fill_data(ObservableCollection<T> data, FlowDocument doc)
        {
            //I only take 25 records from ObservableCollection - to create more Tables
            for (int i = 0; i < data.Count; i += 25)
            {
                var list = (from c in data select c).Skip(i).Take(25);

                 if (i < 25) //Test for only first Table
                {
                    for (int row = 0; row < list.Count(); row++)
                    {
                        TableRow my_cell = new TableRow();

                        foreach (var item in list)
                        {
                            foreach (var w in item as IEnumerable<T>) //ERROR HERE !!!
                            {
                                my_cell.Cells.Add(new TableCell(new Paragraph(new Run(w.ToString()))) { Padding = new Thickness(2), BorderBrush = Brushes.Black, BorderThickness = new Thickness(0.7) });
                            }

                        }

                        TableRowGroup whole_row = new TableRowGroup();
                        whole_row.Rows.Add(my_cell);
                        My_table.RowGroups.Add(whole_row); //I get reference of this elsewhere...
                    }
                }
        }
}

And this is my Employee class :

public class Employee : INotifyPropertyChanged
{
        public string Name { get; set; }
        public string Surname { get; set; }
        public string Address { get; set; }
        public string Country { get; set; }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
}

So in upper case I use ObservableCollection(Employee), and I want to iterate over each Employee in this collection to write values in table row.

Currently this code only writes type into cell, e.g. My_Project.Model.Employee.

Can somebody show me how to do this properly?

P.S.: As you see, I'm following a MVVM approach.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Lucy82
  • 654
  • 2
  • 12
  • 32
  • There is no ForEach extension for IEnumerable, only for List. See: https://stackoverflow.com/a/200584/7147323 – mb14 May 21 '20 at 08:14
  • 2
    foreach (var item in list) gives you an Employee, then how can you foreach the Employee object again ? Do you want to iterate over properties of Employee object ? then you can use typeof(T).GetProperties() which give you an array of PropertyInfo and you can iterate over that. – Athul Raj May 21 '20 at 08:25
  • @AthulRaj, yes that is what I want, iterate over each property and write those values. Can you show me an example? – Lucy82 May 21 '20 at 08:29

2 Answers2

0

Suppose this is a class you have

public class Employee
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Address { get; set; }
    public string Country { get; set; }
}

The below code will produce the following output

    var props = typeof(Employee).GetProperties();

    var employee = new Employee { Name = "Athul", Surname = "Raj", Address = "Blah", Country = "India" };

    foreach (var prop in props)
    {
        Console.WriteLine($"{prop.Name} = {prop.GetValue(employee)}");
    }

    Console.ReadKey();

.

Name = Athul
Surname = Raj
Address = Blah
Country = India

You can use typeof(T).GetProperties() in your method instead of typeof(Employee).GetProperties()

Athul Raj
  • 189
  • 1
  • 9
0

For getting properties and adding value to new cell something like this might work:

var props = item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var p in props) 
{
    my_cell.Cells.Add(new TableCell(new Paragraph(new Run(p.GetValue(this).ToString()))) { Padding = new Thickness(2), BorderBrush = Brushes.Black, BorderThickness = new Thickness(0.7) });
}
ChrisBD
  • 9,104
  • 3
  • 22
  • 35
  • that doesn't work, GetValue takes 2 arguments. – Lucy82 May 21 '20 at 08:48
  • I'll admit that I just copied it from a working piece of code for class cloning: `public object Clone() { var newRecord = Activator.CreateInstance(); var props = newRecord.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanRead); foreach (var p in props) p.SetValue(newRecord, p.GetValue(this)); return newRecord; }` – ChrisBD May 21 '20 at 08:57