Adding Different DataGridView Cell Types to a Column

Have you looked at these:

Mixing cell types in a DataGridViewColumn

DataGridview cells of one column can't have different type

http://social.msdn.microsoft.com/Forums/windows/en-US/148b232b-ce8c-4c49-b35d-50d8a5c448d1/different-cell-types-in-a-datagridview-column

Following from the MSDN article...

There are two ways to do this:

  1. Cast a DataGridViewCell to a certain cell type that exists. For example, convert a DataGridViewTextBoxCell to DataGridViewComboBoxCell type.
  2. Create a control and add it into the controls collection of DataGridView, set its location and size to fit the cell that to be host.

Here's some sample code which illustrates these tricks:

private void Form5_Load(object sender, EventArgs e)
{
    DataTable dt = new DataTable();
    dt.Columns.Add("name");
    for (int j = 0; j < 10; j++)
    {
        dt.Rows.Add("");
    }
    this.dataGridView1.DataSource = dt;
    this.dataGridView1.Columns[0].Width = 200;

    /*
     * First method : Convert to an existed cell type such ComboBox cell,etc
     */

    DataGridViewComboBoxCell ComboBoxCell = new DataGridViewComboBoxCell();
    ComboBoxCell.Items.AddRange(new string[] { "aaa","bbb","ccc" });
    this.dataGridView1[0, 0] = ComboBoxCell;
    this.dataGridView1[0, 0].Value = "bbb";

    DataGridViewTextBoxCell TextBoxCell = new DataGridViewTextBoxCell();
    this.dataGridView1[0, 1] = TextBoxCell;
    this.dataGridView1[0, 1].Value = "some text";

    DataGridViewCheckBoxCell CheckBoxCell = new DataGridViewCheckBoxCell();
    CheckBoxCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
    this.dataGridView1[0, 2] = CheckBoxCell;
    this.dataGridView1[0, 2].Value = true;

    /*
     * Second method : Add control to the host in the cell
     */
    DateTimePicker dtp = new DateTimePicker();
    dtp.Value = DateTime.Now.AddDays(-10);
    //add DateTimePicker into the control collection of the DataGridView
    this.dataGridView1.Controls.Add(dtp);
    //set its location and size to fit the cell
    dtp.Location = this.dataGridView1.GetCellDisplayRectangle(0, 3,true).Location;
    dtp.Size = this.dataGridView1.GetCellDisplayRectangle(0, 3,true).Size;
}

The other answers are way to difficult and error prone. It is way easier to add the required cell type upon request.

Example:

Using the designer, create a form with a DataGridView, and two columns: one for the question and one for the answer.

private DataGridView dataGridView3;
private DataGridViewTextBoxColumn columnQuestion;
private DataGridViewTextBoxColumn columnAnswer;

In my class, I created the enum for the answer type

public enum AnswerType
{
    Text,
    YesNo,
    LoadFile,
    Combo,              
};

I create two methods: one to create a cell that contains a question, and one to create the proper cell type for the answer.

The method to create a question cell is simple:

private DataGridViewCell CreateQuestionCell(string question)
{
    return new DataGridViewTextBoxCell()
    {
        ValueType = typeof(string),
        Value = question,
        ReadOnly = true,       // questions can't be edited
    };
}

The method to create an answer cell has a parameter indicating the desired answer type:

private DataGridViewCell CreateAnswerCell(AnswerType answerType)
{
    // type of column depends on rowIndex
    DataGridViewCell cell;
    switch (answerType)
    {
        case AnswerType.YesNo: // Create a checkbox cell
            cell = new DataGridViewCheckBoxCell()
            {
                ValueType = typeof(bool),
                Value = false,
            };
            break;
        case AnswerType.LoadFile: // Create a Button cell
            cell = new DataGridViewButtonCell()
            {
                ValueType = typeof(string),
                Value = "Load!",
            };
            break;
        case AnswerType.Combo: // Create a Combo Cell
            var selectableValues = Enumerable.Range(0, 4);
            var comboItems = Enumerable.Range(0, 100);
            cell = new DataGridViewComboBoxCell()
            {
                DataSource = new BindingList<int>(comboItems.ToList()),
            };
            break;
        default: // Create a Text cell
            cell = new DataGridViewTextBoxCell()
            {
                ValueType = typeof(string),
                Value = "<please enter name>",
            };
            break;
    }
    return cell;
}

Upon request add a Row, containing a question cell and an answer cell:

private void AddRow(string question, AnswerType answerType)
{
    DataGridViewRow row = new DataGridViewRow();
    row.Cells.Add(this.CreateQuestionCell(question));
    row.Cells.Add(this.CreateAnswerCell(answerType));
    this.dataGridView1.Rows.Add(row);
}

To test I created four buttons and handlers to add rows:

private Button buttonCheckbox;
private Button buttonAction;
private Button buttonCombo;
private Button buttonText;

private void OnButtonCheckbox(object sender, EventArgs e)
{
    this.AddRow("Do you smoke", AnswerType.YesNo);
}

private void OnButtonText(object sender, EventArgs e)
{
    this.AddRow("Name", AnswerType.Text);
}

private void OnButtonCombo(object sender, EventArgs e)
{
    this.AddRow("Age?", AnswerType.Combo);
}

private void OnButtonAction(object sender, EventArgs e)
{
    this.AddRow("Document upload", AnswerType.LoadFile);
}

Et voilà, ça marche! Simple comme bonjour!