简体   繁体   中英

Show List of MyClass to DataGridView

I am trying to display all the data from my List of MyClass to a DataGridView for troubleshooting purposes. So I implemented the code below (from Marc Gravell's post here ) in my application. It executes, but despite the fact that my List contains data, the props.Count and values.Length are always 0. So the DataTable returned has no rows or columns.

What am I doing wrong?

public static DataTable ToDataTable<T>(IList<T> data)
{
    PropertyDescriptorCollection props =
        TypeDescriptor.GetProperties(typeof(T));
    DataTable table = new DataTable();
    for (int i = 0; i < props.Count; i++)
    {
        PropertyDescriptor prop = props[i];
        table.Columns.Add(prop.Name, prop.PropertyType);
    }
    object[] values = new object[props.Count];
    foreach (T item in data)
    {
        for (int i = 0; i < values.Length; i++)
        {
            values[i] = props[i].GetValue(item);
        }
        table.Rows.Add(values);
    }
    return table;
}

My calling code:

dgv.DataSource = Globals.ToDataTable(Lines_Formatted);

My Class:

public class LineData
{
    public string RowID = "";
    public bool MissingMatchingPunch = false;
    public bool ScheduleIssueWithPunches = false;
    public bool ScheduledTimeAmountMet = true;
    public bool Approved_TimeEntry = true;
    public bool Approved_PunchIn = true;
    public bool Approved_PunchOut = true;
    public DateTime DateApplicable = DateTime.MinValue;
    public string TimeType = "";
    public int TimeType_CID = -1;
    public Double HoursWorked = 0;
    public double Amount = 0;
    public DateTime PunchIn = DateTime.MinValue;
    public DateTime PunchOut = DateTime.MinValue;
    public Double DailyTotal = 0;
    public Double CumulativeTotal = 0;
    public string EnteredBy = "";
    public LineType LineTypeKey;
    public enum LineType
    {
        PunchEntry = 1,
        TimeEntry = 2,
        BlankLine = 5
    }
    public string CID_Time = "";
    public string CID_PunchIn = "";
    public string CID_PunchOut = "";
    public string Account_CID = "";
}

You class contains only fields . The code you are using, and data binding and TypeDescriptor services in general require public properties .

To fix the problem, turn your fields into auto properties. If you are using C#6 (VS2015), it will be simple inserting { get; set; } { get; set; } { get; set; } like this

public class LineData
{
    public string RowID { get; set; } = "";
    public bool MissingMatchingPunch { get; set; } = false;
    public bool ScheduleIssueWithPunches { get; set; } = false;
    // ....
}

If you are on older C# version, you need to add { get; set; } { get; set; } { get; set; } part, but move the initialization in the class constructor.

public class LineData
{
    public string RowID { get; set; }
    public bool MissingMatchingPunch { get; set; }
    public bool ScheduleIssueWithPunches { get; set; }
    // ....

    public LineData()
    {
        RowID = "";
        MissingMatchingPunch = false;
        ScheduleIssueWithPunches = false;
        // ...
    }
}

You don't need to initialize properties with default values like false for bool and 0 for int etc.

Finally, after doing that the function should work. But as I mentioned in the comments, once you have a List<LineData> , you can use it directly as a data source for the data grid view - no need to first convert it to a DataTable .

Although Ivan Stoev answered my question above, here is an alternative solution to my question that I have since discovered (thanks to his help), and am now using. This will return a DataTable comprised of the public 'fields' of the Class in the List. Thought it might help someone in the future. Thanks Ivan!

    public static DataTable ToDataTable<T>(List<T> data)
    {

        FieldInfo[] fields = typeof(T).GetFields();

        DataTable table = new DataTable();
        for (int i = 0; i < fields.Length; i++)
        {
            FieldInfo FI = fields[i];
            table.Columns.Add(FI.Name, FI.FieldType);
        }
        object[] values = new object[fields.Length];
        foreach (T item in data)
        {
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = fields[i].GetValue(item);
            }
            table.Rows.Add(values);
        }
        return table;
    }

例如,如果使用List<object>调用该方法,则总是会得到一个空结果,因为object类型没有属性。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM