Search code examples
c#data-bindingdatagridviewdatagridviewcombobox

Bind a datagridviewcolumn to a nested class


In my C# program I have a windows form (Winforms) containing a datagridview. The last column of this datagridview is a datagridviewcomboboxcolumn, and each comboboxcell (in each row) has its own datasource.

As there can be a lot of rows, I want to make a binding to populate the datagridview quickly. I already tried to bind the first columns then populate the datasources of the comboboxes afterwards (in the RowsAdded event), but it takes too much time.

My class Data is as follows :

public class Data
    {
        public string _aaa { get; private set; }

        public string _bbb { get; private set; }

        public string _ccc { get; private set; }

        public List<Room> _rooms_list { get; private set; }
...
}

And the Room class contains the following members :

public ElementId Id { get; }
public virtual string Name { get; set; }

When the datasource of the datagridview is bound to a list of Data objects, I want the corresponding comboboxcell to be filled with the corresponding list of Room objects, with Name as DisplayMember and Id as ValueMember.

I searched on the web but didn't find the answer if it's possible or not.

Thanks a lot for your help.

Edit

More info : I want to let the user select the desired Room among a list of detected/found Rooms, so that's why I chose comboboxes. The results of my calculation already are shown as strings in two of the (bound) string columns.

I also want to make the whole thing sortable, so I use a SortableBindingList to bind the DGV with the list of Data objects : mainDataGridView.DataSource = new SortableBindingList<Data>(_data);


Solution

  • If you have many rooms in your list, it will be slow to create a new combo-box for each cell as you're already experiencing. I recommend creating one combo-box in code and then adding it to each cell.

    Edit: If you're only using the grid for display, you can enhance the performance by simply displaying the rooms as text instead of combo-boxes. You can then denote the selected room by changing the font style (e.g. bold) or color, or by adding some symbol (e.g. asterisk) or word (e.g. [selected]). Separate each room with a new line. Here is an example function, but I don't know how your rooms are selected, so let's assume that you have a bool Selected { get; set; } in your Room class:

    string ListRooms(List<Room> rooms){
        string result = "";
        foreach(Room r in rooms){
            result += r.Selected ? "* " : "";
            result += r.Name + "\r\n";
        }
        return result;
    }
    

    Now in the OnRowsAdded event, you can call this function and display the result in a simple text cell.

    Edit 2: If you're allowing the users to select a room from the list of available rooms, and this list is different from one row to another, then combo-boxes are what we usually use for that purpose. However, if you have many rows then it takes longer to load like you're experiencing.

    In that case, you're best bet is to not load the combo-boxes at the beginning. Leave them empty and when the user clicks on a combo-box to select a room, use Ajax to fetch the list of rooms for that row from the server and populate the combo-box using JavaScript. This solution will perform well, but the page may become a little heavy if the user has to select a room for all rows. I believe that all modern browsers will still be capable of handling it smoothly, but it might become and issue if your users use your web application on a mobile device.

    Alternatively, you can use popups instead of combo-boxes. Replace the combo-boxes with buttons or links. They can read something like "Select a Room". When the user clicks on the button/link, use Ajax to load a popup with a list of available rooms for that row. The user selects a room from the list and clicks the button to close the popup then you display the select room using JavaScript either on the button/link that's used to open the popup, or in a separate column for the selected rooms which can be initially blank. This solution is easier to implement (you can use jQuery or Bootstrap), more flexible (you can display whatever you want on the popup), and performs perfectly regardless of the number of rows.