'Databind Object to Winforms DatagridView with ComboBox

Currently I'm trying to databind object properties to a datagridview. The thing is that the datagridview should have a combobox column, where the user has to choose between two values.

The class in question is this one:

 public class SingleTableRow
    {

    /// <summary>
    /// Input für datagrid
    /// </summary>
    public string PropertyName { get; set; }
    public string VaultProperty { get; set; }
    public string SageProperty { get; set; }
    public bool IsSync { get; set; }
    public bool AreSame { get; set; }
    public bool IsSageLeading { get; set; }
    /// <summary>
    /// Single Table row constructor
    /// </summary>
    /// <param name="allValues"></param>
    public SingleTableRow(List<string> allValues)
    {
        PropertyName = allValues[0];
        VaultProperty = allValues[1];
        SageProperty = allValues[2];
        IsSync = false;
        IsSageLeading = true;
        AreSame = VaultProperty.Equals(SageProperty);


    }
}

All values except IsSync should be bound to the Datagridview. The IsSageLeading is a Boolean and indicates, which of the two values should be preselected for the user (Vault or Sage).

Once it is done it should look like this:

Datagridview

I already have a implementation but it only works by creating a DataTable for the String values and then adding a column with combo boxes after that. This is obviously bad design because the last column does not get sorted and does not contain the values of the object.

        dtgrid.DataSource = table;
            .
            .
            .
        DataGridViewComboBoxColumn combo = new DataGridViewComboBoxColumn();
        combo.HeaderText = "Führendes System";
        combo.Name = "Führendes System";

        String[] options = { "Vault", "Sage" };
        combo.Items.AddRange(options);
        dtgrid.Columns.Add(combo);

How do I apporach this problem best?



Solution 1:[1]

It sounds like you need to map the Boolean values from IsSageLeading to one of the two values you want to display (Vault or Sage). As you have already noted, that since the combo box column is NOT part of the data source, then it acts independently from the GRIDS data source.

The code below should allow you to bind the IsSageLeading property to the combo box column such that a false value will display as “Vault” and a true value will be displayed as “Sage.”

There are three properties of the combo box column we need to focus on…The first is the columns DataPropertyName. This will point to the column in the GRIDS data source… namely the Boolean IsSageLeading property.

Next, we need to create a data source for the Combo Box Column. This data source will be a DataTable with two fields and two rows. The first field which is called ValueMem is a Boolean type. The second field which is called DisplayMem is a string field. The entire table may look something like below…

ValueMem DisplayMem
False Vault
True Sage

This table will be used as a DataSource for the Combo Box Column. The properties we need to set for the column are the ValueMember and DisplayMember which will obviously point to each of the two fields in the combo boxes data source.

The code below should enable you to bind the Boolean IsSageLeading property to the combo box column. About the only thing to note is that you need to add the combo box column BEFORE you set the Grids DataSource.

private void Form1_Load(object sender, EventArgs e) {
  dataGridView1.Columns.Add(GetComboColumn());
  dataGridView1.DataSource = GetGridData();
  dataGridView1.Columns["Fuhrendes System"].DisplayIndex = 3;
}


private DataGridViewComboBoxColumn GetComboColumn() {
  DataTable dt = new DataTable();
  dt.Columns.Add("ValueMem", typeof(bool));
  dt.Columns.Add("DisplayMem", typeof(string));
  dt.Rows.Add(false, "Vault");
  dt.Rows.Add(true, "Sage");
  DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
  col.HeaderText = "Fuhrendes System";
  col.Name = "Fuhrendes System";
  col.DataSource = dt;
  col.DataPropertyName = "IsSageLeading";
  col.ValueMember = "ValueMem";
  col.DisplayMember = "DisplayMem";
  return col;
}

private DataTable GetGridData() {
  DataTable dt = new DataTable();
  dt.Columns.Add("PropertyName", typeof(string));
  dt.Columns.Add("VaultProperty", typeof(string));
  dt.Columns.Add("SageProperty", typeof(string));
  dt.Columns.Add("IsSync", typeof(bool));
  dt.Columns.Add("AreSame", typeof(bool));
  dt.Columns.Add("IsSageLeading", typeof(bool));
  Random rand = new Random();
  for (int i = 1; i < 10; i++) {
    dt.Rows.Add("PropertyName " + i,
      "VaultProperty " + i,
      "SageProperty " + i,
      rand.Next(2) == 1,
      rand.Next(2) == 1,
      rand.Next(2) == 1
    );
  }
  return dt;
}

This should allow the combo box column to act as a part of the grids data source and not detached as previously described… i.e., sorting and filtering should include the IsSageLeading column. I hope this makes sense and helps.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1