This isn't just a 'complex binding' this is a Pivot, where you are wanting to transform detail repeating data (the list o' cheezburgers) to a single row, and that row has an undetermined number of columns.
I believe your best option here is to write a custom serializer that will allow you to transform your data into rows in an xml datatable and then bind to that. Since your column count is going to be inconsistent xml will be more forgiving, though I am not sure how the DataGridView will handle it.
EDIT FOLLOWS
Since I did not 'know' how the DataGridView would handle the XML DataTable I decided to write it up and test it. I works how I expected, and I believe how you will want.
Here are your cat & cheezburger classes (slightly modified)
public class Cat
{
public string Name { get; set; }
public string Description { get; set; }
public List<Cheezburger> Cheezbugers { get; private set; }
public void AddCheezburger(Cheezburger cheezburger)
{
if (this.Cheezbugers == null)
this.Cheezbugers = new List<Cheezburger>();
this.Cheezbugers.Add(cheezburger);
}
};
public class Cheezburger
{
public int PattyCount { get; set; }
public bool CanHaz { get; set; }
};
Then you need to create simple form with two buttons "bind to object" (button1) and "bind to datatable" (button2), with a DataGridView anchored to the bottom. and code up the form like:
//in the editor this next line is in the codeblock, once I save it it isn't..
public partial class Form1 : Form
{
List<Cat> cats = new List<Cat>();
public Form1()
{
InitializeComponent();
cats.Add(new Cat() { Name = "Felix", Description = "Classic Cat" });
cats.Add(new Cat() { Name = "Garfield", Description = "Fat,Lazy" });
cats.Add(new Cat() { Name = "Tom", Description = "Wanna-Be-Mouser" });
cats[0].AddCheezburger(new Cheezburger() { CanHaz = true, PattyCount = 1 });
cats[0].AddCheezburger(new Cheezburger() { CanHaz = false, PattyCount = 3 });
cats[1].AddCheezburger(new Cheezburger() { CanHaz = false, PattyCount = 2 });
cats[1].AddCheezburger(new Cheezburger() { CanHaz = true, PattyCount = 7 });
cats[1].AddCheezburger(new Cheezburger() { CanHaz = true, PattyCount = 99 });
cats[2].AddCheezburger(new Cheezburger() { CanHaz = true, PattyCount = 5 });
cats[2].AddCheezburger(new Cheezburger() { CanHaz = false, PattyCount = 14 });
}
private void button1_Click(object sender, EventArgs e)
{
dataGridView1.DataSource = null;
dataGridView1.DataSource = cats;
}
private void button2_Click(object sender, EventArgs e)
{
dataGridView1.DataSource = null;
dataGridView1.DataSource = serializeCats(cats);
}
private DataTable serializeCats(List<Cat> cats)
{
DataTable returnTable = new DataTable("Cats");
returnTable.Columns.Add(new DataColumn("Name"));
returnTable.Columns.Add(new DataColumn("Description"));
int setID = 1;
foreach (Cat cat in cats)
{
//If the row requires more columns than are present then add additional columns
int totalColumnsRequired = (cat.Cheezbugers.Count * 2) + 2;
while (returnTable.Columns.Count < totalColumnsRequired)
{
returnTable.Columns.Add(new DataColumn("Can Haz " + setID.ToString()));
returnTable.Columns.Add(new DataColumn("Patty Count " + setID.ToString()));
setID++;
}
returnTable.AcceptChanges();
DataRow row = returnTable.NewRow();
row[0] = cat.Name;
row[1] = cat.Description;
int cbi = 2; //cheezburger index
foreach (Cheezburger cheezburger in cat.Cheezbugers)
{
row[cbi] = cheezburger.CanHaz;
cbi++;
row[cbi] = cheezburger.PattyCount;
cbi++;
}
returnTable.Rows.Add(row);
}
return returnTable;
}
}
Do not attempt to predefine the DataGridView columns, they will be created dynamically based on the data source. Binding to the list of cats will get you two columns (name/description) Binding to the DataTable gets 8 columns, name & description + 6 columns of cheezburger info, lined up as (I believe) you want.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…