Zeus Zeus - 1 month ago 9
C# Question

Bind a linkedlist to a datagridview

I'm trying to bind a linkedlist to a datagridview. The method below works for the properties in the class except the array.
If I declare the array as a new instance the linkedlist is created correctly, but the array is not bound into the datagridview.
If the array is created as a property (I think the code is correct) causes

An unhandled exception of type 'System.StackOverflowException' occurred
when the linkedlist is created.

Thanks for any help.

public class PayoffNode
{
public int DealNo { get; set; }
public string Category { get; set; }
public string Strategy { get; set; }
public string GreekType { get; set; }
// declare array as instance or as a property?
//public double[] Data = new double[22];
public double[] Data
{
get { return Data; }
set { Data = value; }
}
}

LinkedList<Globals.PayoffNode> PayLL = new LinkedList<Globals.PayoffNode>();
Random Rnd = new Random();
for (int K = 1; K <= 10; K++)
{
var T = new Globals.PayoffNode();
T.Category = "Account==" + K;
T.GreekType = "Greek==" + K;
T.DealNo = K;
T.Strategy = "Strategy==" + K;
for (int DP = 1; DP <= 21; DP++)
{
T.Data[DP] = Rnd.Next(10, 99);
}
PayLL.AddLast(T);
}

List<Globals.PayoffNode> qP = (from P in PayLL
where P.Category == "Account==4" && P.DealNo == 4 && P.GreekType == "Greek==4" && P.Strategy == "Strategy==4"
select P).ToList();

PayoffTable.DataSource = qP;


Update:
Thanks for the comments, this seems to be working.

public class PayoffNode
{
public int DealNo { get; set; }
public string Category { get; set; }
public string Strategy { get; set; }
public string GreekType { get; set; }
public double Data1 { get; set; }
public double Data2 { get; set; }
public double Data3 { get; set; }
public double[] Data = new double[22];
}

LinkedList<Globals.PayoffNode> PayLL = new LinkedList<Globals.PayoffNode>();
Random Rnd = new Random();
for (int K = 1; K <= 10; K++)
{
var T = new Globals.PayoffNode();
T.Category = "Account==" + K;
T.GreekType = "Greek==" + K;
T.DealNo = K;
T.Strategy = "Strategy==" + K;
for (int DP = 1; DP <= 21; DP++)
{
T.Data[DP] = Rnd.Next(10, 99);
}
PayLL.AddLast(T);
}

List<Globals.PayoffNode> qP = (from P in PayLL
where P.Category == "Account==4" && P.DealNo == 4 && P.GreekType == "Greek==4" && P.Strategy == "Strategy==4"
select new Globals.PayoffNode()
{
Category=P.Category,
DealNo=P.DealNo,
GreekType=P.GreekType,
Strategy=P.Strategy,
Data1=P.Data[1],
Data2 = P.Data[2],
Data3 = P.Data[3],
}).ToList();

PayoffTable.DataSource = qP;

Answer

One way to avoid making 21 Data properties is to convert the List to DataTable:

class PayoffNode
{
    public int DealNo;
    public string Category;
    public double[] Data; // = new double[21];
}

and then

Random Rnd = new Random();

List<PayoffNode> PayLL = Enumerable.Range(1, 10).Select(i => new PayoffNode {
    DealNo = i,
    Category = "Account==" + i,
    Data = Enumerable.Range(1, 21).Select(d => (double)Rnd.Next(10, 99)).ToArray()
}).ToList();

// List<PayoffNode> to DataTable
var dt = new DataTable();
dt.Columns.Add("DealNo", typeof(int));
dt.Columns.Add("Category"); // typeof(string) by default
for (int i = 1; i <= 21; i++)
    dt.Columns.Add("Data" + i, typeof(double));

foreach (var P in PayLL)
{
    var dr = dt.Rows.Add(P.DealNo, P.Category);
    for (int i = 0; i < 21; i++)
        dr[i+2] = P.Data[i]; // +2 is the number of fields before the Data fields
}

PayoffTable.DataSource = dt;
dt.DefaultView.RowFilter = " Category = 'Account==4' ";

The advantage is that you set the DataSource only once and just change the RowFilter to filter it. Also, any changes made in the DataGridView change the DataTable and vice-versa.

Note that arrays in C# and most other languages start from 0 and not from 1 ( .Data[0] to access the first item in the array ), so the for loop to access the Data array in my example is from 0 to 20.