Afnan Bashir
Afnan Bashir

Reputation: 7419

Add multiple checkedListbox to columns of datagrid View

As we can Add single checkbox to column to datagrid view column but is it possible to add checked list box to datagrid view the aim is to have a cell having multiple checkboxes.

How can we add them?

How can we access their properties,such as text and checked ?

Got some answer but i cannot understand it http://social.msdn.microsoft.com/Forums/en/winformsdatacontrols/thread/6c68a44c-c4ab-4caf-94e9-249ec63a90d0

Upvotes: 1

Views: 8900

Answers (2)

Jeremy Thompson
Jeremy Thompson

Reputation: 65554

Read my comments at the bottom of this answer before using this code.


As per the question how can we access text and checkboxes from this CheckListBox DataGridView Column :

public class CheckedListBoxColumn : DataGridViewColumn
{
    public CheckedListBoxColumn()
        : base(new CheckedListBoxCell())
    {
    }

    public override DataGridViewCell CellTemplate
    {
        get
        {
            return base.CellTemplate;
        }
        set
        {
            if (value != null &&
                !value.GetType().IsAssignableFrom(typeof(CheckedListBoxCell)))
            {
                throw new InvalidCastException("Must be a CheckedListBoxCell");
            }
            base.CellTemplate = value;
        }
    }
}

public class CheckedListBoxCell : DataGridViewCell
{
    public CheckedListBoxCell()
        : base()
    {

    }

    public override void InitializeEditingControl(int rowIndex, object
        initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
    {
        // Set the value of the editing control to the current cell value.  
        base.InitializeEditingControl(rowIndex, initialFormattedValue,
            dataGridViewCellStyle);
        CheckedListBoxEditingControl ctl =
            DataGridView.EditingControl as CheckedListBoxEditingControl;
        InitializeCheckedListBox(ctl, (ICollection)this.FormattedValue);
    }
    private void InitializeCheckedListBox(CheckedListBox ctrl, ICollection value)
    {
        ctrl.Items.Clear();
        foreach (object obj in value)
        {
            ctrl.Items.Add(obj.ToString());
        }
        ctrl.Tag = this.Value;
    }
    public override Type EditType
    {
        get
        {
            return typeof(CheckedListBoxEditingControl);
        }
    }
    protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, System.ComponentModel.TypeConverter valueTypeConverter, System.ComponentModel.TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
    {
        if (value == null)
        {
            return new List<object>();
        }
        return base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
    }
    public override Type FormattedValueType
    {
        get
        {
            return typeof(ICollection);
        }
    }
    public override Type ValueType
    {
        get
        {
            return typeof(ICollection);
        }
    }
    private CheckedListBox internalControl;

    protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
    {
        base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
        graphics.FillRectangle(new SolidBrush(cellStyle.BackColor), cellBounds);

        if (internalControl == null)
        {
            internalControl = new CheckedListBox();
        }
        internalControl.Items.Clear();
        ICollection collection = value as ICollection;
        if (collection != null)
        {
            foreach (object obj in collection)
            {
                internalControl.Items.Add(obj);
            }
            Bitmap bmp = new Bitmap(cellBounds.Width, cellBounds.Height);
            internalControl.DrawToBitmap(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
            graphics.DrawImage(bmp, cellBounds, new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
        }
    }
    protected override void OnClick(DataGridViewCellEventArgs e)
    {
        this.DataGridView.BeginEdit(false);
        base.OnClick(e);
    }
}

class CheckedListBoxEditingControl : CheckedListBox, IDataGridViewEditingControl
{
    DataGridView dataGridView;
    private bool valueChanged = false;
    int rowIndex;

    public CheckedListBoxEditingControl()
    {

    }

    // Implements the IDataGridViewEditingControl.EditingControlFormattedValue   
    // property.  
    public object EditingControlFormattedValue
    {
        get
        {
            return this.Tag;
        }
        set
        {
            //  this.Tag = value;  
        }
    }

    // Implements the   
    // IDataGridViewEditingControl.GetEditingControlFormattedValue method.  
    public object GetEditingControlFormattedValue(
        DataGridViewDataErrorContexts context)
    {
        return EditingControlFormattedValue;
    }

    // Implements the   
    // IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.  
    public void ApplyCellStyleToEditingControl(
        DataGridViewCellStyle dataGridViewCellStyle)
    {
        this.Font = dataGridViewCellStyle.Font;
        this.ForeColor = dataGridViewCellStyle.ForeColor;
        this.BackColor = dataGridViewCellStyle.BackColor;
    }

    // Implements the IDataGridViewEditingControl.EditingControlRowIndex   
    // property.  
    public int EditingControlRowIndex
    {
        get
        {
            return rowIndex;
        }
        set
        {
            rowIndex = value;
        }
    }

    // Implements the IDataGridViewEditingControl.EditingControlWantsInputKey   
    // method.  
    public bool EditingControlWantsInputKey(
        Keys key, bool dataGridViewWantsInputKey)
    {
        // Let the DateTimePicker handle the keys listed.  
        switch (key & Keys.KeyCode)
        {
            case Keys.Left:
            case Keys.Up:
            case Keys.Down:
            case Keys.Right:
            case Keys.Home:
            case Keys.End:
            case Keys.PageDown:
            case Keys.PageUp:
                return true;
            default:
                return !dataGridViewWantsInputKey;
        }
    }

    // Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit   
    // method.  
    public void PrepareEditingControlForEdit(bool selectAll)
    {
        // No preparation needs to be done.  
    }

    // Implements the IDataGridViewEditingControl  
    // .RepositionEditingControlOnValueChange property.  
    public bool RepositionEditingControlOnValueChange
    {
        get
        {
            return false;
        }
    }

    // Implements the IDataGridViewEditingControl  
    // .EditingControlDataGridView property.  
public DataGridView EditingControlDataGridView
{
    get
    {
        return dataGridView;
    }
    set
    {
        dataGridView = value;
    }
}

// Implements the IDataGridViewEditingControl  
// .EditingControlValueChanged property.  
public bool EditingControlValueChanged
{
    get
    {
        return valueChanged;
    }
    set
    {
        valueChanged = value;
    }
}

// Implements the IDataGridViewEditingControl  
// .EditingPanelCursor property.  
public Cursor EditingPanelCursor
{
    get
    {
        return base.Cursor;
    }
}
}    

An interesting Blog post covers the problems with this class: http://dotnetgenetics.blogspot.com.au/2014/01/custom-checkedlistbox-datagridview.html

Add a property in the CheckedListBoxCell class to retrieve the checked items:

 public ICollection CheckedItems
 {
    get
    {
        if (internalControl == null)
            return null;
        else
        {
            if (internalControl != null)
            {
                if (internalControl.CheckedItems.Count > 0)
                {
                    return internalControl.CheckedItems;
                }
                else
                {
                    if ((CheckedListBox)this.DataGridView.Rows[RowIndex].Cells[ColumnIndex].DataGridView.EditingControl != null)
                    {
                        CheckedListBox checks = (CheckedListBox)this.DataGridView.Rows[RowIndex].Cells[ColumnIndex].DataGridView.EditingControl;
                        if (checks.CheckedItems.Count > 0)
                            return checks.CheckedItems;
                        else
                            return null;
                    }
                    else
                        return null;
                }
            }
            else
            {
                return null;
            }
        }
    }
}  

This is the method to get the checked items.

 private void btnShow_Click(object sender, EventArgs e)  
 {  
   StringBuilder builder = new StringBuilder();  
   foreach (DataGridViewRow item in dgCheckListColumn1.Rows)  
   {  
     DataGridViewCell cell = item.Cells[1];  
     if (((cell as CheckedListBoxCell).CheckedItems != null))  
     {  
       if (((cell as CheckedListBoxCell).CheckedItems.Count > 0))  
       {  
         foreach (var checkItem in ((cell as CheckedListBoxCell).CheckedItems))  
         {  
           builder.AppendLine(String.Format("Row {0} : item: {1}", item.Index + 1, checkItem.ToString()));  
         }  
         builder.AppendLine(Environment.NewLine);  
       }   
     }  
   }  
   MessageBox.Show("Checked Items: \n" + builder.ToString());  
 }  


My take on all this is - its crap - looks crap and it behaves like crap.. even feels crap:

enter image description here


IMHO its much better tapping into a DataGridView's cell click event and popping up a CheckedListbox:

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == 1)
    {
        int RowHeight1 = DataGridView1.Rows[e.RowIndex].Height;
        Rectangle CellRectangle1 = DataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);

        CellRectangle1.X += DataGridView1.Left;
        CellRectangle1.Y += DataGridView1.Top + RowHeight1;


        checkedListBox1.Left = CellRectangle1.X;
        checkedListBox1.Top = CellRectangle1.Y;
        checkedListBox1.Visible = true;
    }
}

enter image description here

Upvotes: 4

Jamie Ide
Jamie Ide

Reputation: 49261

You can do this by creating a custom DataGridView column. There are many articles on the web that demonstrate this; here's one example. Expose the checkboxes as properties to access their properties.

Upvotes: 1

Related Questions