How to create multi-select dropdown in a cell of WinForms Grid?
Multi-select dropdown grid
To create a cell that has multi-selection dropdown grid, you have to use a derived custom cell from the GridDropDownGridCellModel and the GridDropDownGridCellRenderer. In the derived renderer, the code embeds the WinForms Grid Control whose ListBoxSelectionMode is set to MultiSimple. The renderer uses the DropDownContainerCloseDropDown override to move the text in the selected rows of the embedded grid into a string that is set into the style. The CellValue of the cell in the parent grid that hosts this custom cell type lists the selected options as a hyphen delimited string for every column and the New Line delimited string for every row.
Creating CellModel:
The custom cell model is Derived from the GridDropDownGridCellModel. The custom cell renderer object is invoked by the CreateRenderer() method.
C#
//Deriving the GridDropDownGridCellModel. public class DropDownGridCellModel : GridDropDownGridCellModel { private GridControlBase _embbeddedGrid; public GridControlBase EmbeddedGrid { get { if (_embbeddedGrid == null) _embbeddedGrid = new GridControlBaseImp(); return _embbeddedGrid; } set { _embbeddedGrid = value; } } protected DropDownGridCellModel(SerializationInfo info, StreamingContext context) : base(info, context) { } public DropDownGridCellModel(GridModel grid) : base(grid) { } public override GridCellRendererBase CreateRenderer(GridControlBase control) { return new DropDownGridCellRenderer(control, this); } }
VB
'Deriving the GridDropDownGridCellModel. Public Class DropDownGridCellModel Inherits GridDropDownGridCellModel Private _embbeddedGrid As GridControlBase Public Property EmbeddedGrid() As GridControlBase Get If _embbeddedGrid Is Nothing Then _embbeddedGrid = New GridControlBaseImp() End If Return _embbeddedGrid End Get Set(ByVal value As GridControlBase) _embbeddedGrid = value End Set End Property Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext) MyBase.New(info, context) End Sub Public Sub New(ByVal grid As GridModel) MyBase.New(grid) End Sub Public Overrides Function CreateRenderer(ByVal control As GridControlBase) As GridCellRendererBase Return New DropDownGridCellRenderer(control, Me) End Function End Class 'Override the CreateRenderer() in the Base class. Public Overrides Function CreateRenderer(ByVal control As GridControlBase) As GridCellRendererBase 'Return the Custom Renderer Object. Return New FolderBrowserCellRenderer(control, Me) End Function End Class
Creating CellRenderer:
The behavior of the cell is defined in the custom cell renderer.
C#
//Deriving the GridDropDownGridCellRenderer. public class DropDownGridCellRenderer : GridDropDownGridCellRenderer { GridControl grid; public DropDownGridCellRenderer(GridControlBase grid, GridCellModelBase cellModel) : base(grid, cellModel) { //Disable the TextBox in the base class renderer. this.DisableTextBox = true; //Add the DropDown Button as the ComboBox button. DropDownButton = new GridCellComboBoxButton(this); this.grid = null; } }
VB
'Deriving the GridDropDownGridCellRenderer. Public Class DropDownGridCellRenderer Inherits GridDropDownGridCellRenderer Private grid As GridControl Public Sub New(ByVal grid As GridControlBase, ByVal cellModel As GridCellModelBase) MyBase.New(grid, cellModel) 'Disable the TextBox in the base class renderer. Me.DisableTextBox = True 'Add the DropDown Button as the ComboBox button DropDownButton = New GridCellComboBoxButton(Me) Me.grid = Nothing End Sub End Class
Overrides in DropDownGridCellRenderer class:
The custom cell renderer class needs to override the following methods to implement the Multi-Select DropDown cell.
C#
protected override void OnInitialize(int rowIndex, int colIndex) { this.grid = ((DropDownGridCellModel)this.Model).EmbeddedGrid as GridControl; this.grid.Dock = DockStyle.Fill; //Sets the Selection Type of the DropDownGrid. this.grid.ListBoxSelectionMode = SelectionMode.MultiSimple; base.OnInitialize(rowIndex, colIndex); } protected override void InitializeDropDownContainer() { base.InitializeDropDownContainer(); //this.DropDownContainer.FormBorderStyle = FormBorderStyle.SizableToolWindow; this.DropDownContainer.IgnoreDialogKey = true; } //Changes the ControlValue if dropdown was closed with Done. public override void DropDownContainerCloseDropDown(object sender, PopupClosedEventArgs e) { this.Grid.Model[this.RowIndex, this.ColIndex].Text = this.ParseString(); // To measure the Width and Height of the parsed string with corresponding font of the Grid. Size s = this.grid.CreateGraphics().MeasureString(this.Grid.Model[this.RowIndex, this.ColIndex].Text, this.Grid.Model[this.RowIndex, this.ColIndex].Font.GdipFont).ToSize(); //Sets the Value of the Height and width to the Grid. //this.Grid.Model.RowHeights[this.RowIndex] = s.Height + 10 ; //this.Grid.Model.ColWidths[this.ColIndex] = s.Width + 20 ; Grid.InvalidateRange(GridRangeInfo.Cell(RowIndex, ColIndex), GridRangeOptions.MergeCoveredCells); // Merge all cells base.DropDownContainerCloseDropDown(sender, e); } //Used to parse the values in the Cells. private string ParseString() { string str = ""; //Get the range for selected rows. GridRangeInfoList gridList = this.grid.Selections.GetSelectedRows(true, true); //Gets the Enumarator from RangeList IEnumerator ie = gridList.GetEnumerator(); while (ie.MoveNext()) { //To replace the string where R is found. string paresedString = Regex.Replace(ie.Current.ToString(), "R", ""); //Matches the ':' for finding ranges. if (Regex.Match(paresedString, ":").Success) { //Matches the digits in the Range. Match m = Regex.Match(paresedString, @"\d+"); if (m.Success) { int rowBegin = int.Parse(m.Value); int rowEnd = 0; if (m.NextMatch().Success) { rowEnd = int.Parse(m.NextMatch().Value); } // fetches the values to the cells and store into the string called str. // Column values are separator by hyphen '-' // row values are separator by '\n'; for (int k = rowBegin; k <= rowEnd; k++) { for (int i = 0; i < this.grid.Model.ColCount; i++) { str += this.grid.Model[k, i].Text + "-"; } str += "\n"; } } } else { int row = int.Parse(paresedString); //To parse the single row. for (int i = 0; i < this.grid.Model.ColCount; i++) { str += this.grid.Model[row, i].Text + "-"; } str += "\n"; } } return str; } //Create the DropDown Grid and its styles. protected override Control CreateInnerControl(out GridControlBase grid) { grid = this.grid; grid.Dock = DockStyle.Fill; grid.CausesValidation = false; return grid; }
VB
Protected Overrides Sub OnInitialize(ByVal rowIndex As Integer, ByVal colIndex As Integer) Me.grid = TryCast((CType(Me.Model, DropDownGridCellModel)).EmbeddedGrid, GridControl) Me.grid.Dock = DockStyle.Fill 'Sets the Selection Type of the DropDownGrid. Me.grid.ListBoxSelectionMode = SelectionMode.MultiSimple MyBase.OnInitialize(rowIndex, colIndex) End Sub Protected Overrides Sub InitializeDropDownContainer() MyBase.InitializeDropDownContainer() 'this.DropDownContainer.FormBorderStyle = FormBorderStyle.SizableToolWindow; Me.DropDownContainer.IgnoreDialogKey = True End Sub 'Used to change the ControlValue if dropdown was closed with Done. Public Overrides Sub DropDownContainerCloseDropDown(ByVal sender As Object, ByVal e As PopupClosedEventArgs) Me.Grid.Model(Me.RowIndex, Me.ColIndex).Text = Me.ParseString() ' To measure the Width and Height of the parsed string with corresponding font of the Grid. Dim s As Size = Me.grid.CreateGraphics().MeasureString(Me.Grid.Model(Me.RowIndex, Me.ColIndex).Text, Me.Grid.Model(Me.RowIndex, Me.ColIndex).Font.GdipFont).ToSize() 'Sets the Value of the Height and width to the Grid. 'this.Grid.Model.RowHeights[this.RowIndex] = s.Height + 10 ; 'this.Grid.Model.ColWidths[this.ColIndex] = s.Width + 20 ; Grid.InvalidateRange(GridRangeInfo.Cell(RowIndex, ColIndex), GridRangeOptions.MergeCoveredCells) ' Merge all cells MyBase.DropDownContainerCloseDropDown(sender, e) End Sub 'Used to parse the values in the Cells Private Function ParseString() As String Dim str As String = "" 'Get the range for selected rows. Dim gridList As GridRangeInfoList = Me.grid.Selections.GetSelectedRows(True, True) 'Gets the Enumarator from RangeList. Dim ie As IEnumerator = gridList.GetEnumerator() Do While ie.MoveNext() 'To replace the string where R is found. Dim paresedString As String = Regex.Replace(ie.Current.ToString(), "R", "") 'Matches the ':' for finding ranges. If Regex.Match(paresedString, ":").Success Then 'Matches the digits in the Range. Dim m As Match = Regex.Match(paresedString, "\d+") If m.Success Then Dim rowBegin As Integer = Integer.Parse(m.Value) Dim rowEnd As Integer = 0 If m.NextMatch().Success Then rowEnd = Integer.Parse(m.NextMatch().Value) End If 'Fetches the values to the cells and store into the string called str. 'Column values are separator by hyphen '-' 'Row values are separator by '\n'; For k As Integer = rowBegin To rowEnd For i As Integer = 0 To Me.grid.Model.ColCount - 1 str &= Me.grid.Model(k, i).Text & "-" Next i str &= Constants.vbLf Next k End If Else Dim row As Integer = Integer.Parse(paresedString) 'To parse the single row. For i As Integer = 0 To Me.grid.Model.ColCount – 1 str &= Me.grid.Model(row, i).Text & "-" Next i str &= Constants.vbLf End If Loop Return str End Function 'Create the DropDown Grid and it's styles. Protected Overrides Function CreateInnerControl(<System.Runtime.InteropServices.Out()> ByRef grid As GridControlBase) As Control grid = Me.grid grid.Dock = DockStyle.Fill grid.CausesValidation = False Return grid End Function
Adding CellModel:
The object is created for the DropDownGridCellModel and it is added to the GridControl.CellModel.
C#
//Creates the instance of the DropdownGrid Model. DropDownGridCellModel dropDownModel = new DropDownGridCellModel(this.gridControl1.Model); dropDownModel.EmbeddedGrid = GridA; //To register the DropDownGridCellModel to the GridModel. gridControl1.CellModels.Add("MultiSelectDropDown", dropDownModel);
VB
'Creates the instance of the DropdownGrid Model. Dim dropDownModel As New DropDownGridCellModel(Me.gridControl1.Model) dropDownModel.EmbeddedGrid = GridA 'To register the DropDownGridCellModel to the GridModel. gridControl1.CellModels.Add("MultiSelectDropDown", dropDownModel)
Assigning CellType:
C#
//Set the cell type to the FolderBrowser. this.gridControl1[2, 3].CellType = "MultiSelectDropDown"; private void button1_Click(object sender, EventArgs e) { //Writes the Selected Items in The DropDownGrid to the Output. Console.WriteLine(this.gridControl1[2, 3].CellValue.ToString()); }
VB
'Set the cell type to the FolderBrowser. Private Me.gridControl1(2, 3).CellType = "MultiSelectDropDown" Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) 'Writes the Selected Items in The DropDownGrid to the Output. Console.WriteLine(Me.gridControl1(2, 3).CellValue.ToString()) End Sub
Figure 1: Multi-Select DropDown in Grid Control
Figure 2: Selected Items in the DropDown
Samples:
Conclusion
I hope you enjoyed learning about how to create multi-select dropdown in a cell of WinForms Grid.
You can refer to our WinForms GridControl feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications. You can also explore our WinForms GridControl example to understand how to create and manipulate data.
For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.
If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!