Popular way (1, 2) for custom painting of items in DataGridViewComboBox is handling of event DataGridView1.EditingControlShowing and setting up DrawItem event handlers there:
private void dataGridView1_EditingControlShowing(
object sender,
DataGridViewEditingControlShowingEventArgs e)
{
theBoxCell = (ComboBox) e.Control;
theBoxCell.DrawItem += theBoxCell_DrawItem;
theBoxCell.DrawMode = DrawMode.OwnerDrawVariable;
}
You see what is wrong: it uses control-level event to handle work for columns. But what if I have 50+ datagridviews? Painting of custom combo boxes should be handled per column instance, leaving control level intact.
Minimal implementation of per-column handling is below. The only problem I have is that OnDrawItem()
method is not getting called. What am I missing? (You can see that fuchsia background override from the same class is working.)
(To reproduce, just paste the following into class file and add column of type DataGridViewCustomPaintComboBoxColumn to your DataGridView1.)
public class DataGridViewCustomPaintComboBoxColumn : DataGridViewComboBoxColumn
{
public DataGridViewCustomPaintComboBoxColumn()
{
base.New();
CellTemplate = new DataGridViewCustomPaintComboBoxCell();
}
}
public class DataGridViewCustomPaintComboBoxCell : DataGridViewComboBoxCell
{
public override Type EditType {
get { return typeof(DataGridViewCustomPaintComboBoxEditingControl); }
}
protected override void Paint(...)
{
//painting stuff for incative cells here - works well
}
}
public class DataGridViewCustomPaintComboBoxEditingControl : DataGridViewComboBoxEditingControl
{
public override Color BackColor { // property override only for testing
get { return Color.Fuchsia; } // test value works as expected
set { base.BackColor = value; }
}
protected override void OnPaint(PaintEventArgs e) // never called - why?
{
base.OnPaint(e)
}
protected override void OnDrawItem(DrawItemEventArgs e) // never called - why?
{
base.OnDrawItem(e)
}
}
The only problem I have is that OnDrawItem() method is not getting called. What am I missing?
What you see inside a focussed DataGridViewComboBoxCell
is pretty much a 'real' ComboBox
and you need a reference to it in order to hook into its DrawItem
event! (You can have a look the Controls collection of the DGV to see that there is one more when a ComboBoxCell has focus.. DataGridViewComboBoxEditingControl
is directly descended from ComboBox
)
Note: One difference to an out of the box CombBox
is that is has set DrawMode = OwnerDrawVariable
by default. If you want to replace it by something you create yourself, don't forget to set it in code!
Looks like that is what you are missing!
If you can create your own DataGridViewComboBoxEditingControl
and make it appear in your DGV you're all set.
An alternative model I often use is a sort of 'Decorator', that implements the custom drawing for all columns you register with it.
DgvCombBoxPainter.Register(DataGridView dgv, stringOrInt columnNameOrIndex..)
In the registration function it would hook into the necessary DGV methods, that is EditingControlShowing
to get at the ComboBox
you see, when the DGV has focus and the CellPainting
for the other cases.
The decorator can be static and needs only one ComboBox
for all columns you have registered, as only one can have focus at a time..
If you can handle all painting code in the decorator all the better. From the events it can always reach back to the DataGridView
via sender
and the cells' properties via the DataGridViewCellPaintingEventArgs
parameter..
You can even put a reference to the current cell into the ComboBox
reference's Tag
:
theBoxCell.Tag = dataGridView1.CurrentCell;
If you want you could also provide individual delegates to call in the paint event(s) when registering. You would then have to keep a list of those, maybe in a Dictionary..
来源:https://stackoverflow.com/questions/31466145/how-to-make-custom-datagridviewcombobox-dependent-only-on-its-datagridviewcombob