Click here to Skip to main content
Licence CPOL
First Posted 24 Mar 2008
Views 80,741
Downloads 3,577
Bookmarked 85 times

How to Host a Color Picker Combobox in Windows Forms DataGridView Cells

By | 24 Mar 2008 | Article
An article on how to add a color picker ComboBox to DataGridView

Introduction

The .NET Framework provides quite a rich collection of UI controls and components for WinForms development. There is one particular control that has been missing. I am talking about a color-picker control with drop down color selection capabilities, just like the one used within the Visual Studio .NET property browser for editing Color-typed properties.

A color picker control was developed by Palo Mraz and was published in this Website. I wanted to use this control in a DataGridView but I couldn't find any example on how to do it. The only available examples on how to use custom control in DataGridView were to do with textual controls. This custom control involves graphics and not just text. I have decided to publish this article for the benefit of other fellow developers who would like to have a color picker combo box hosted by a DataGridView.

Background

For those of you who want to get some background on the color picker combo box, please refer to "The ColorPicker WinForms Control".

You can get background on how to host custom controls in DataGridView cells here.

Color Picker in DataGridView

The core requirement for my project was to display the same drop down color selector that is used within WinForm’s PropertyGrid control inside a DataGridView.

The DataGridView control provides several properties that you can use to adjust the appearance and basic behavior (look and feel) of its cells, rows, and columns. My requirement was to show the color itself next to a text showing the color’s name.

In order to do that, I had to implement owner drawing for the control and extend its capabilities by creating custom cells, columns, and rows.

ColorPickerColumn Class

This class creates a custom column for hosting a column of color picker cells. It inherits from DataGridViewColumn and overrides the property CellTemplate.

public override DataGridViewCell CellTemplate
{
    get
    {
        return base.CellTemplate;
    }
    set
    {
        // Ensure that the cell used for the template is a ColorPickerCell.
        if (value != null && 
            !value.GetType().IsAssignableFrom(typeof(ColorPickerCell)))
        {
            throw new InvalidCastException("Must be a ColorPicker");
        }
        base.CellTemplate = value;
    }
}

ColorPickerCell Class

This class creates a custom cell for hosting the color picker combo box and it inherits from DataGridViewTextBoxCell. In order to draw the content of the cell in the way I wanted, I overrode the paint method.

 protected override void Paint(Graphics graphics,
           Rectangle clipBounds, Rectangle cellBounds, int rowIndex,
           DataGridViewElementStates elementState, object value,
           object formattedValue, string errorText,
           DataGridViewCellStyle cellStyle,
           DataGridViewAdvancedBorderStyle advancedBorderStyle,
           DataGridViewPaintParts paintParts)
{
    formattedValue = null;
    
    base.Paint(graphics, clipBounds, cellBounds, rowIndex, 
            elementState, value, formattedValue,
               errorText, cellStyle, advancedBorderStyle, paintParts);

   
    Rectangle ColorBoxRect = new Rectangle();
    RectangleF TextBoxRect = new RectangleF();
    GetDisplayLayout(cellBounds, ref ColorBoxRect, ref TextBoxRect);

    /// Draw the cell background, if specified.
    if ((paintParts & DataGridViewPaintParts.Background) ==
        DataGridViewPaintParts.Background)
    {
        SolidBrush cellBackground;
        if (value != null && value.GetType() == typeof(Color))
        {
            cellBackground = new SolidBrush((Color)value);
        }
        else
        {
            cellBackground =  new SolidBrush(cellStyle.BackColor);
        }
        graphics.FillRectangle(cellBackground, ColorBoxRect);
        graphics.DrawRectangle(Pens.Black, ColorBoxRect);
        Color lclcolor=(Color)value;
        graphics.DrawString(lclcolor.Name.ToString(), cellStyle.Font, 
            System.Drawing.Brushes.Black, TextBoxRect);
    
        cellBackground.Dispose();
    }
}

The other method that I had to override is ParseFormattedValue. When the user picks a custom color from the list, he or she gets a Hex number of this color. There is a slight problem with this number: it doesn't get the 0x prefix added to it. This causes the System.Number.StringToNumber method to generate an exception. The .NET environment tries to convert this string to an integer and fails as without the 0x prefix it cannot be regarded as a Hex number, hence this method adds the prefix when required.

public override object ParseFormattedValue
    object formattedValue, DataGridViewCellStyle cellStyle, 
         System.ComponentModel.TypeConverter formattedValueTypeConverter, 
         System.ComponentModel.TypeConverter valueTypeConverter)
{
    int result;
    string number = "0x" + formattedValue.ToString();
    if (int.TryParse(formattedValue.ToString(), 
        stem.Globalization.NumberStyles.HexNumber, null, out result))
        //Hex number
        return base.ParseFormattedValue("0x" + formattedValue.ToString(), 
            lStyle, formattedValueTypeConverter, valueTypeConverter);
    else
        return base.ParseFormattedValue(formattedValue, cellStyle, 
            mattedValueTypeConverter, valueTypeConverter);
}

ColorPickerControl Class

This class creates the custom control to be hosted by the ColorPickerCell. It implements the interface IDataGridViewEditingControl and overrides the OnLeave event of the original ColorPicker control. OnLeave – This event calls NotifyDataGridViewOfValueChange to notify the DataGridView that the contents of the cell have changed.

protected override void OnLeave(EventArgs eventargs)
{
    // Notify the DataGridView that the contents of the cell
    // have changed.
    base.OnLeave(eventargs);
    NotifyDataGridViewOfValueChange();
}

Using the Code

I created a form named ExampleForm containing a DataGridView control. This grid has two columns: the first is a simple textbox column and the second is the ColorPicker column. In this form, I demonstrate how to load and save the data containing colors and names to and from an XML file named ColorData.xml. The file should be stored in the same folder of the executable.

History

  • March 25th, 2008: Initial release

About the Author

I live in New Zealand. I've been doing Microsoft Windows development for the past 6 years.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Joe20033

Software Developer

New Zealand New Zealand

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionPlease help [modified] Pinmemberopium_210021003:44 25 Feb '10  
GeneralProject in VB PinmemberPaolippo2:54 24 Jan '10  
GeneralDual monitor problem with popup of colorcombobox Pinmemberjcgsell14:57 11 Nov '09  
GeneralProblem with the splitter leaving a trail in the editing control. [modified] PinmemberMember 33644968:10 7 Sep '09  
Generalsub grid in grid Pinmemberdrorby1:59 9 Jul '09  
GeneralUnable to change color according to the options that i choose. Pinmemberlousyprogrammer22:20 25 Mar '09  
GeneralRe: Unable to change color according to the options that i choose. PinmemberJoe2003318:25 20 Apr '09  
GeneralA nice simple example PinmemberColin Eberhardt4:11 17 Nov '08  
GeneralRe: A nice simple example PinmemberJoe200338:25 19 Nov '08  
GeneralMy Custom control remains clipped within the Datagridview PinmemberTheCubanP3:26 29 Oct '08  
GeneralActivating the Cell PinmemberAli Rafiee6:37 8 Jul '08  
GeneralRe: Activating the Cell PinmemberJoe2003313:29 9 Jul '08  
GeneralRe: Activating the Cell PinmemberAli Rafiee5:22 10 Jul '08  
QuestionCan you make multiple cells remain in edit mode in the DataGridView? [modified] PinmemberDeadHead74:09 20 Jun '08  
AnswerRe: Can you make multiple cells remain in edit mode in the DataGridView? PinmemberJoe2003313:34 9 Jul '08  
QuestionVB wanted? Pinmemberdherrmann6:22 5 Apr '08  
AnswerRe: VB wanted? PinmemberJoe2003310:27 7 Apr '08  
AnswerRe: VB wanted? PinmemberJoe2003313:53 15 Apr '08  
GeneralValue Not Staying In Control After Leaving Cell Pinmemberxiaolinmantis8:13 29 Mar '08  
GeneralRe: Value Not Staying In Control After Leaving Cell PinmemberJoe2003311:06 30 Mar '08  
GeneralRe: Value Not Staying In Control After Leaving Cell Pinmemberxiaolinmantis2:48 1 Apr '08  
Hi,
 
Thanks for the reply, but I am already doing as you suggested. Here is my code:
 
------------------------------
 
//Source: http://www.codeproject.com/KB/cs/DataGridColorPicker.aspx?msg=2486298#xx2486298xx
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
 
namespace ControlLibrary.DataGrids.Columns
{
public class DataGridViewColorPickerColumn : DataGridViewColumn
{
public DataGridViewColorPickerColumn()
: base(new DataGridViewColorPickerCell())
{
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
// Ensure that the cell used for the template is a CalendarCell.
if (value != null &&
!value.GetType().IsAssignableFrom(typeof(DataGridViewColorPickerCell)))
{
throw new InvalidCastException("Must be a ColorPicker");
}
base.CellTemplate = value;
}
}
}
public class DataGridViewColorPickerCell : DataGridViewTextBoxCell
{
DataGridViewColorPickerControl _ColorPicker;
public DataGridViewColorPickerCell()
: 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);
DataGridViewColorPickerControl ctl = DataGridView.EditingControl as
DataGridViewColorPickerControl;
_ColorPicker = ctl;
 
if (this.Value != null && (this.Value.GetType() == typeof(Color)))
{
ctl.Color = (Color)this.Value;
}
}
public override Type EditType
{
get
{
//Return the type of the editing contol that CalendarCell uses.
return typeof(DataGridViewColorPickerControl);
}
}
public override Type ValueType
{
get
{
// Return the type of the value that CalendarCell contains.
return typeof(Color);
}
}
public override object DefaultNewRowValue
{
get
{
// Use the current date and time as the default value.
return Color.White;
}
}
protected override void Paint(Graphics graphics,
Rectangle clipBounds, Rectangle cellBounds, int rowIndex,
DataGridViewElementStates elementState, object value,
object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
formattedValue = null;
 
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue,
errorText, cellStyle, advancedBorderStyle, paintParts);
 
Rectangle ColorBoxRect = new Rectangle();
RectangleF TextBoxRect = new RectangleF();
GetDisplayLayout(cellBounds, ref ColorBoxRect, ref TextBoxRect);
 
//// Draw the cell background, if specified.
if ((paintParts & DataGridViewPaintParts.Background) ==
DataGridViewPaintParts.Background)
{
SolidBrush cellBackground;
if (value != null && value.GetType() == typeof(Color))
{
cellBackground = new SolidBrush((Color)value);
}
else
{
cellBackground = new SolidBrush(cellStyle.BackColor);
}
graphics.FillRectangle(cellBackground, ColorBoxRect);
graphics.DrawRectangle(Pens.Black, ColorBoxRect);
try
{
Color lclcolor = (Color)value;
 
graphics.DrawString(lclcolor.Name.ToString(), cellStyle.Font, System.Drawing.Brushes.Black, TextBoxRect);
 
cellBackground.Dispose();
}
catch
{
}
}
 
}
public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle,
System.ComponentModel.TypeConverter formattedValueTypeConverter,
System.ComponentModel.TypeConverter valueTypeConverter)
{
int result;
string number = "0x" + formattedValue.ToString();
if (int.TryParse(formattedValue.ToString(), System.Globalization.NumberStyles.HexNumber, null, out result))
//Hex number
return base.ParseFormattedValue("0x" + formattedValue.ToString(), cellStyle, formattedValueTypeConverter, valueTypeConverter);
else
return base.ParseFormattedValue(formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
}
protected virtual void GetDisplayLayout(Rectangle CellRect, ref Rectangle colorBoxRect, ref RectangleF textBoxRect)
{
const int DistanceFromEdge = 2;
 
colorBoxRect.X = CellRect.X + DistanceFromEdge;
colorBoxRect.Y = CellRect.Y + 1;
colorBoxRect.Size = new Size((int)(1.5 * 17), CellRect.Height - (2 * DistanceFromEdge));
 
// The text occupies the middle portion.
textBoxRect = RectangleF.FromLTRB(colorBoxRect.X + colorBoxRect.Width + 5,
colorBoxRect.Y + 2, CellRect.X + CellRect.Width - DistanceFromEdge,
colorBoxRect.Y + colorBoxRect.Height);
}
}
class DataGridViewColorPickerControl : LaMarvin.Windows.Forms.ColorPicker, IDataGridViewEditingControl
{
DataGridView dataGridView;
private bool valueChanged = false;
int rowIndex;
 
public DataGridViewColorPickerControl()
{
}
 
// Implements the IDataGridViewEditingControl.EditingControlFormattedValue
// property.
public object EditingControlFormattedValue
{
get
{
return this;
}
set
{
this.Color = Color.Pink;
}
}
// Implements the
// IDataGridViewEditingControl.GetEditingControlFormattedValue method.
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
{
return Color.Name;
}
// Implements the
// IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
public void ApplyCellStyleToEditingControl(
DataGridViewCellStyle dataGridViewCellStyle)
{
this.Font = dataGridViewCellStyle.Font;
}
// 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
public Cursor EditingPanelCursor
{
get
{
return base.Cursor;
}
}
protected virtual void NotifyDataGridViewOfValueChange()
{
this.valueChanged = true;
if (this.dataGridView != null)
{
this.dataGridView.NotifyCurrentCellDirty(true);
}
}
protected override void OnLeave(EventArgs eventargs)
{
// Notify the DataGridView that the contents of the cell
// have changed.
base.OnLeave(eventargs);
NotifyDataGridViewOfValueChange();
}
protected override void OnTextChanged(EventArgs e)
{
valueChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
base.OnTextChanged(e);
}
}
}
------------------------------
 
Hope you can help.
Regards
 
Matt
GeneralRe: Value Not Staying In Control After Leaving Cell PinmemberJoe2003317:28 1 Apr '08  
GeneralRe: Value Not Staying In Control After Leaving Cell Pinmemberxiaolinmantis22:40 2 Apr '08  
GeneralRe: Value Not Staying In Control After Leaving Cell PinmemberJoe2003313:53 15 Apr '08  
GeneralRe: Value Not Staying In Control After Leaving Cell Pinmemberxiaolinmantis21:11 15 Apr '08  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120529.1 | Last Updated 24 Mar 2008
Article Copyright 2008 by Joe20033
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid