I was able to solve this using a DataTable as your datasource for the Grid. I don't like the idea of moving from a nice clean object to a DataTable, but it provides support for the dynamic binding you need. I modified your friend object to have a few constructors. This allowed me to cleanup the static code declaration but might not be necessary in your implmentation.
The basic idea is that you will step through all possible friends, add their name as a DataColumn in a DataTable, then fill in the data for all person objects and their respective friends. This could probably be written to work in a single iteration of the allPerson object but I preferred two iterations to make the code easier to read.
The solution is written for c# 3.5 but could be converted for older versions by changing the static data declaration. I hope this helps.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// setup your person object with static data for testing
List<person> allPerson = new List<person>()
{
new person()
{
name = "Dan",
age = 21,
allMyFriends = new List<friend>() { new friend("James"), new friend("John"), new friend("Matt") }
},
new person()
{
name = "James",
age = 21,
allMyFriends = new List<friend>() { new friend("Dan"), new friend("Matt"), new friend("Tom") }
},
new person()
{
name = "John",
age = 21,
allMyFriends = new List<friend>() { new friend("Dan") }
},
new person()
{
name = "Matt",
age = 21,
allMyFriends = new List<friend>() { new friend("Dan"), new friend("James") }
},
new person()
{
name = "Tom",
age = 21,
allMyFriends = new List<friend>() { new friend("James") }
}
};
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Age");
foreach (person p in allPerson)
{
// step through each person and look at their friends
foreach (friend f in p.allMyFriends)
{
// look to see if this friend has a column already
if (!dt.Columns.Contains(f.name))
{
dt.Columns.Add(f.name);
}
}
}
foreach (person p in allPerson)
{
// create the datarow that represents the person
System.Data.DataRow dr = dt.NewRow();
dr["Name"] = p.name;
dr["Age"] = p.age;
// find the friends and mark them
foreach (friend f in p.allMyFriends)
{
dr[f.name] = "X";
}
dt.Rows.Add(dr);
}
// fill the list
this.Grid.DataSource = dt;
this.Grid.DataBind();
}
}
public class person
{
public string name;
public int age;
public List<friend> allMyFriends = new List<friend>();
}
public class friend
{
public string name;
public string address;
public friend()
{
}
public friend(string name)
{
this.name = name;
}
public friend(string name, string address)
{
this.name = name;
this.address = address;
}
}
Edit:
I forgot to add how this is rendered.
-------------------------------------------------
| Name | Age | James | John | Matt | Dan | Tom |
-------------------------------------------------
| Dan | 21 | X | X | X | | |
| James | 21 | | | X | X | X |
| John | 21 | | | | X | |
| Matt | 21 | X | | | X | |
| Tom | 21 | X | | | | |
-------------------------------------------------