Question

I need some help with the DataGridView class in Windows Forms, I don't know if it's just me but I am really struggling with this class programmatically.

You would think that a simple task as adding a Column as a ComboBox to a DataGridView would be a piece of cake, but apparently it's not! The reason I need to do it programmatically is because I need multiple ComboBoxes on each Row in the DataGridView where the selectable drop down items will be dependent on selections in one or more of the others etc...

Here is how I initialize my DataGridView.

private void InitializeDataGridView()
{
    _objectDataGridView.AutoGenerateColumns = false;
    _objectDataGridView.Columns.Add(new DataGridViewTextBoxColumn
                                        {
                                                DataPropertyName = "Id",
                                                HeaderText = "Id",
                                                ValueType = typeof(int)
                                        });
    _objectDataGridView.Columns.Add(new DataGridViewTextBoxColumn
                                        {
                                                DataPropertyName = "Name",
                                                HeaderText = "Name",
                                                ValueType = typeof(string),
                                                AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
                                        });
    var objectTypeComboBoxColumn = new DataGridViewComboBoxColumn
                                       {
                                               DataPropertyName = "Type",
                                               HeaderText = "Object Type",
                                               ValueType = typeof(ObjectType),
                                               ValueMember = "Id",
                                               DisplayMember = "Name",
                                               DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox
                                       };
    _objectDataGridView.Columns.Add(objectTypeComboBoxColumn);
    var containerComboBoxColumn = new DataGridViewComboBoxColumn
                                      {
                                              DataPropertyName = "Container",
                                              HeaderText = "Container",
                                              ValueType = typeof(Container),
                                              ValueMember = "Id",
                                              DisplayMember = "Name",
                                              DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox
                                      };
    _objectDataGridView.Columns.Add(containerComboBoxColumn);
}

Up to this point everything is well and good. Now when I click a TreeNodeDecorator (derived from TreeNode) in a TreeView the OnBeforeSelect event fires of which I am listening to. I then use the TreeNodeDecorator.Id to retrieve a list of associated objects, via Fluent NHibernate (ORM).

With the newly retrieved list I want to clear and then fill the _objectDataGridView with new Rows. In the method listening to the OnBeforeSelect event I then try to set the _objectDataGridView.DataSource like this.

private void SetDataSource(IEnumerable<Object> assignedObjects)
{
    var dataTable = new DataTable();
    dataTable.Columns.Add("Id");
    dataTable.Columns.Add("Name");
    dataTable.Columns.Add("Type");
    dataTable.Columns.Add("Container");
    foreach(var assignedObject in assignedObjects)
    {
        dataTable.Rows.Add(assignedObject.Id,
                           assignedObject.Name,
                           assignedObject.ObjectType,
                           assignedObject.Container);
    }
    _objectDataGridView.DataSource = dataTable;
}

But I haven't gotten to set the selectable items for the DataGridViewComboBoxColumns. I could have set a static set of selectable items when I created the DataGridViewComboBoxColumns, but I need those items to be added dynamically and individually per row and in accordance with selected items in other comboboxes on the same row. And I'm really not sure of how to do that.

I guess there is an event I need to listen to, and from there fill the DataGridViewComboBoxColumns.Items or DataGridViewComboBoxColumns.DataSource with the correct items. I then also need to listen to when selections changes in these ComboBoxes and fill / change up the selectable items in related ComboBoxes.

Was it helpful?

Solution

I ended up adding the Rows to the DataGridView like this:

private void SetDataSource(IEnumerable<Object> assignedObjects, 
                           List<Container> subContainersAssociatedWithSystem)
{
    _objectDataGridView.Rows.Clear();
    foreach (var assignedObject in assignedObjects)
    {
        var newRowIndex = _objectDataGridView.Rows.Add();
        var row = _objectDataGridView.Rows[newRowIndex];
        row.Cells["Id"].Value = assignedObject.Id;
        row.Cells["Name"].Value = assignedObject.Name;
        var containerColumn = (DataGridViewComboBoxCell)row.Cells["Container"];
        containerColumn.DataSource = subContainersAssociatedWithSystem;
        containerColumn.Value = assignedObject.Container.Id;
        var objectTypeColumn = (DataGridViewComboBoxCell)row.Cells["Type"];
        objectTypeColumn.DataSource = new List<ObjectType> {assignedObject.ObjectType};
        objectTypeColumn.Value = assignedObject.ObjectType.Id;
    }
}

And then listen to the EditingControlShowing event like this:

private void InitializeDataGridView()
{
    ...
    _objectDataGridView.EditingControlShowing += (sender, e) =>
    {
        var cb = e.Control as ComboBox;
        if (_objectDataGridView.CurrentCellAddress.X == objectTypeComboBoxColumn.DisplayIndex && cb != null)
        {
            var value = _objectDataGridView[containerComboBoxColumn.DisplayIndex, _objectDataGridView.CurrentCellAddress.Y].Value;
            if(value != null)
            {
                var containerId = (int)value;
                using(var dao = _daoFactory.Create(_daoAdminRole))
                {
                    var container = dao.Get<Container>(containerId);
                    var objectTypes = dao.GetByQueryObject(new ObjectTypeQueryObject {ContainerType = new ContainerType {Id = container.ContainerType.Id}});
                    cb.DataSource = objectTypes;
                }
            }
        }
    };
    ...
}

Now when I click the objectTypeComboBoxColumn the DataSource gets set with the correct items according to the selection in the containerComboBoxColumn.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top