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.