I have a gridview which is populated from a dataset returned from Sql Server. The stored procedure that returns the data (which is a cross tab query) generates the columns dynamically (as the data on screen will look like a report).

The data is about users and, depending on the criterion passed to the stored procedure, the columns might be called [Bill],[Jim],[Mick] etc. or, with a different parameter passed to the stored procedure .. [Linda],[John],[Jane],[Fred]

The data is a list of users as columns and the rows contain a list of skills.

So the data might look like:

Skill______Bill______Jim______Mick
Word_____1|27____2|27_____3|27
Excel_____1|34____2|34_____3|34

The data like '1|27' is the UserID and SkillID concatenated - which is returned in the dataset.

On screen I want it to like like the data above but with a checkbox at the intersections of the user and skill - and the value of the checkbox needs to be set to be the UserID|SkillID pair (as it were).

Normally, I'd do something like this when populating the GridView:

Code:
 gvUserSkills.DataSource = ds.Tables[2];
        gvUserSkills.DataKeyNames = new string[] { "UserID", "SkillID", "UserName" };
        gvUserSkills.DataBind();
because, normally, I know what the column names are (because I've said: 'SELECT UserID, UserName, SkillID FROM etc.' to get the data.

But here the columns are dynamically generated.

So, my question is - how can I loop through the columns in my dataset assigning the Column Names (in this case [Bill],[Jim],[Mick] etc.) to the DataKeyNames collection?

Thanks for any help.