Tuesday, December 7, 2010

DataGridView Custom CheckBox Column

I lately had a need to a checkbox column in a DataGridView, but with custom images (plus, minus and a question mark). DataGridViewCheckBoxColumn images cannot be changed, so I had two options: Customize the OnPaint event, or recreate a new DataGridViewColumn.

I decided to go on the second option. I created a DataGridViewThreeStateCheckBoxColumn class(I prefer long names on abbreviations):

public class DataGridViewThreeStateCheckBoxColumn : DataGridViewImageColumn
{
public DataGridViewThreeStateCheckBoxColumn(ImageList images, bool isThreeState)
{
this.CellTemplate = new DataGridViewThreeStateCheckBoxCell(images, isThreeState, true);
}
}


And a DataGridViewThreeStateCheckBoxCell class:

public enum eState {Unknown = 0, Positive = 1, Negative = 2}
public class DataGridViewThreeStateCheckBoxCell : DataGridViewImageCell
{
private Dictionary StateToImage { get; set; }

private bool IsReadOnly { get; set; }

private eState cellState;
public eState CellState
{
get
{
return cellState;
}
set
{
cellState = value;
this.Value = StateToImage[cellState];
}
}

public DataGridViewThreeStateCheckBoxCell()
{
}

public DataGridViewThreeStateCheckBoxCell(ImageList images, bool isThreeState, bool isReadOnly)
{
StateToImage = new Dictionary { { eState.Unknown, images.Images["question-mark"] }, { eState.Positive, images.Images["plus"] } };
if(isThreeState)
StateToImage[eState.Negative] = images.Images["minus"];
CellState = eState.Unknown;
IsReadOnly = isReadOnly;
}

protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
{
if (IsReadOnly)
return;

// toggle the cell state
CellState = ((eState)(((int)CellState + 1) % StateToImage.Count));

base.OnMouseClick(e);
}
}


In may case I also need a way to notify the parent on state changes, to update a database. I did this by creating an event that the parent was able to register to.