I recently created a custom combo box with a button and now I am trying to create a data grid view column that uses that control. I have tried a few different methods including trying to build the new control inside a custom editing control. I have been able to get the control to show but the Button does not paint correctly nor is it clickable. The drop down won’t show. and if I click the drop down arrow while the control is showing I get a null reference error in the protected override void WndProc(ref Message m).
The Idea for this control is to be able to click the button within the combobox to add items to the datasource. The ComboBoxWithButton Control works perfectly on it’s own but once I try to host it in a datagridview cell everything stops working.
Here is the control I want to host in the datagridview
`
<code>public class ComboBoxWithButton : ComboBox
private static int DROPDOWNBUTTON_WIDTH = 17;
private static int BUTTON_WIDTH = 17;
private Button customButton;
if (customButton == null)
customButton = new Button()
FlatStyle = ButtonFlatStyle,
TextAlign = ButtonTextAlign,
TextImageRelation = ButtonTextImageRelation
customButton.FlatAppearance.BorderSize = 0;
customButton.SizeChanged += CustomButton_SizeChanged;
private void CustomButton_SizeChanged(object sender, EventArgs e)
BUTTON_WIDTH = customButton.Width;
[Browsable(true), Description("Occurs when the component is clicked."), Category("Button")]
public event EventHandler<EventArgs> ButtonClicked;
[Browsable(true), Description("The button text associated with the control"), Category("Button")]
if (customButton == null)
return GetDefaultValue<string>(this, "ButtonText");
return customButton.Text;
set { customButton.Text = value; }
[Browsable(true), Description("Determines the appearance of the control when a user moves the mouse over the control and clicks."), Category("Button")]
[DisplayName("FlatStyle")]
[DefaultValue(FlatStyle.Flat)]
public FlatStyle ButtonFlatStyle
if (customButton == null)
return GetDefaultValue<FlatStyle>(this, "ButtonFlatStyle");
return customButton.FlatStyle;
set { customButton.FlatStyle = value; }
[Browsable(true), Description("The alignment of the text that will be displayed on the control."), Category("Button")]
[DisplayName("TextAlign")]
[DefaultValue(System.Drawing.ContentAlignment.MiddleCenter)]
public System.Drawing.ContentAlignment ButtonTextAlign
if (customButton == null)
return GetDefaultValue<System.Drawing.ContentAlignment>(this, "ButtonTextAlign");
return customButton.TextAlign;
set { customButton.TextAlign = value; }
[Browsable(true), Description("Specifies the relative location of the image to the text on the button."), Category("Button")]
[DisplayName("TextImageRelation")]
[DefaultValue(TextImageRelation.Overlay)]
public TextImageRelation ButtonTextImageRelation
if (customButton == null)
return GetDefaultValue<TextImageRelation>(this, "ButtonTextImageRelation");
return customButton.TextImageRelation;
set { customButton.TextImageRelation = value; }
[Browsable(true), Description("The button image associated with the control"), Category("Button")]
if (customButton == null)
return GetDefaultValue<Image>(this, "ButtonImage");
return customButton.Image;
set { customButton.Image = value; }
[Browsable(true), Description("Indicates if the button associated with the control is always visable"), Category("Button")]
[DisplayName("ButtonAlwaysVisible")]
public bool ButtonAlwaysVisible { get; set; }
static T GetDefaultValue<T>(object obj, string propertyName)
if (obj == null) return default(T);
var prop = obj.GetType().GetProperty(propertyName);
if (prop == null) return default(T);
var attr = prop.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attr.Length != 1) return default(T);
return (T)((DefaultValueAttribute)attr[0]).Value;
public ComboBoxWithButton()
CustomButton.Click += CustomButton_Click;
protected internal int EditControlOffset { get; set; } = 4;
protected override void OnHandleCreated(EventArgs e)
UpdateControlsPosition();
protected override void WndProc(ref Message m)
case NativeMethods.WM_WINDOWPOSCHANGED:
UpdateControlsPosition();
case NativeMethods.WM_DESTROY:
if (customButton != null)
customButton.Click -= CustomButton_Click;
private void UpdateControlsPosition()
if (customButton != null)
Rectangle arrowRect = NativeMethods.GetComboBoxInfoInternal(Handle, out Rectangle editRect, out IntPtr editHwnd);
if (arrowRect.IsEmpty || editRect.IsEmpty) return;
// Same size as the Arrow Button: change as required
DROPDOWNBUTTON_WIDTH = arrowRect.Width;
customButton.Size = arrowRect.Size;
customButton.Location = new Point(arrowRect.Left - customButton.Width - 1, 1);
editRect.Width = ClientSize.Width - customButton.Width * 2 - EditControlOffset;
NativeMethods.SetWindowPos(editHwnd, IntPtr.Zero, 0, 0, editRect.Width, editRect.Height, NativeMethods.SWP_Flags);
private void CustomButton_Click(object sender, EventArgs e) => OnEditButtonClicked(e);
protected virtual void OnEditButtonClicked(EventArgs e)
ButtonClicked?.Invoke(this, e);
internal static Rectangle GetComboArrowBounds(Rectangle bounds)
return new Rectangle(bounds.Right - DROPDOWNBUTTON_WIDTH, bounds.Top, DROPDOWNBUTTON_WIDTH, bounds.Height);
internal static Rectangle GetComboButtonBounds(Rectangle bounds)
return new Rectangle(bounds.Right - BUTTON_WIDTH - BUTTON_WIDTH, bounds.Top, BUTTON_WIDTH, bounds.Height);
<code>public class ComboBoxWithButton : ComboBox
{
private static int DROPDOWNBUTTON_WIDTH = 17;
private static int BUTTON_WIDTH = 17;
private Button customButton;
Button CustomButton
{
get
{
if (customButton == null)
{
customButton = new Button()
{
Text = ButtonText,
FlatStyle = ButtonFlatStyle,
Parent = this,
TextAlign = ButtonTextAlign,
TextImageRelation = ButtonTextImageRelation
};
customButton.FlatAppearance.BorderSize = 0;
}
customButton.SizeChanged += CustomButton_SizeChanged;
return customButton;
}
}
private void CustomButton_SizeChanged(object sender, EventArgs e)
{
BUTTON_WIDTH = customButton.Width;
}
[Browsable(true), Description("Occurs when the component is clicked."), Category("Button")]
[DisplayName("Click")]
public event EventHandler<EventArgs> ButtonClicked;
[Browsable(true), Description("The button text associated with the control"), Category("Button")]
[DisplayName("Text")]
[DefaultValue("?")]
public string ButtonText
{
get
{
if (customButton == null)
{
return GetDefaultValue<string>(this, "ButtonText");
}
else
{
return customButton.Text;
}
}
set { customButton.Text = value; }
}
[Browsable(true), Description("Determines the appearance of the control when a user moves the mouse over the control and clicks."), Category("Button")]
[DisplayName("FlatStyle")]
[DefaultValue(FlatStyle.Flat)]
public FlatStyle ButtonFlatStyle
{
get
{
if (customButton == null)
{
return GetDefaultValue<FlatStyle>(this, "ButtonFlatStyle");
}
else
{
return customButton.FlatStyle;
}
}
set { customButton.FlatStyle = value; }
}
[Browsable(true), Description("The alignment of the text that will be displayed on the control."), Category("Button")]
[DisplayName("TextAlign")]
[DefaultValue(System.Drawing.ContentAlignment.MiddleCenter)]
public System.Drawing.ContentAlignment ButtonTextAlign
{
get
{
if (customButton == null)
{
return GetDefaultValue<System.Drawing.ContentAlignment>(this, "ButtonTextAlign");
}
else
{
return customButton.TextAlign;
}
}
set { customButton.TextAlign = value; }
}
[Browsable(true), Description("Specifies the relative location of the image to the text on the button."), Category("Button")]
[DisplayName("TextImageRelation")]
[DefaultValue(TextImageRelation.Overlay)]
public TextImageRelation ButtonTextImageRelation
{
get
{
if (customButton == null)
{
return GetDefaultValue<TextImageRelation>(this, "ButtonTextImageRelation");
}
else
{
return customButton.TextImageRelation;
}
}
set { customButton.TextImageRelation = value; }
}
[Browsable(true), Description("The button image associated with the control"), Category("Button")]
[DisplayName("Image")]
public Image ButtonImage
{
get
{
if (customButton == null)
{
return GetDefaultValue<Image>(this, "ButtonImage");
}
else
{
return customButton.Image;
}
}
set { customButton.Image = value; }
}
[Browsable(true), Description("Indicates if the button associated with the control is always visable"), Category("Button")]
[DisplayName("ButtonAlwaysVisible")]
[DefaultValue(false)]
public bool ButtonAlwaysVisible { get; set; }
static T GetDefaultValue<T>(object obj, string propertyName)
{
if (obj == null) return default(T);
var prop = obj.GetType().GetProperty(propertyName);
if (prop == null) return default(T);
var attr = prop.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attr.Length != 1) return default(T);
return (T)((DefaultValueAttribute)attr[0]).Value;
}
public ComboBoxWithButton()
{
CustomButton.Click += CustomButton_Click;
}
[DefaultValue(8)]
protected internal int EditControlOffset { get; set; } = 4;
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
UpdateControlsPosition();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case NativeMethods.WM_WINDOWPOSCHANGED:
UpdateControlsPosition();
break;
case NativeMethods.WM_DESTROY:
if (customButton != null)
{
customButton.Click -= CustomButton_Click;
customButton.Dispose();
}
break;
}
}
private void UpdateControlsPosition()
{
if (customButton != null)
{
SuspendLayout();
Rectangle arrowRect = NativeMethods.GetComboBoxInfoInternal(Handle, out Rectangle editRect, out IntPtr editHwnd);
if (arrowRect.IsEmpty || editRect.IsEmpty) return;
// Same size as the Arrow Button: change as required
DROPDOWNBUTTON_WIDTH = arrowRect.Width;
customButton.Size = arrowRect.Size;
customButton.Location = new Point(arrowRect.Left - customButton.Width - 1, 1);
editRect.Width = ClientSize.Width - customButton.Width * 2 - EditControlOffset;
NativeMethods.SetWindowPos(editHwnd, IntPtr.Zero, 0, 0, editRect.Width, editRect.Height, NativeMethods.SWP_Flags);
ResumeLayout(false);
}
}
private void CustomButton_Click(object sender, EventArgs e) => OnEditButtonClicked(e);
protected virtual void OnEditButtonClicked(EventArgs e)
{
ButtonClicked?.Invoke(this, e);
}
internal static Rectangle GetComboArrowBounds(Rectangle bounds)
{
return new Rectangle(bounds.Right - DROPDOWNBUTTON_WIDTH, bounds.Top, DROPDOWNBUTTON_WIDTH, bounds.Height);
}
internal static Rectangle GetComboButtonBounds(Rectangle bounds)
{
return new Rectangle(bounds.Right - BUTTON_WIDTH - BUTTON_WIDTH, bounds.Top, BUTTON_WIDTH, bounds.Height);
}
}
</code>
public class ComboBoxWithButton : ComboBox
{
private static int DROPDOWNBUTTON_WIDTH = 17;
private static int BUTTON_WIDTH = 17;
private Button customButton;
Button CustomButton
{
get
{
if (customButton == null)
{
customButton = new Button()
{
Text = ButtonText,
FlatStyle = ButtonFlatStyle,
Parent = this,
TextAlign = ButtonTextAlign,
TextImageRelation = ButtonTextImageRelation
};
customButton.FlatAppearance.BorderSize = 0;
}
customButton.SizeChanged += CustomButton_SizeChanged;
return customButton;
}
}
private void CustomButton_SizeChanged(object sender, EventArgs e)
{
BUTTON_WIDTH = customButton.Width;
}
[Browsable(true), Description("Occurs when the component is clicked."), Category("Button")]
[DisplayName("Click")]
public event EventHandler<EventArgs> ButtonClicked;
[Browsable(true), Description("The button text associated with the control"), Category("Button")]
[DisplayName("Text")]
[DefaultValue("?")]
public string ButtonText
{
get
{
if (customButton == null)
{
return GetDefaultValue<string>(this, "ButtonText");
}
else
{
return customButton.Text;
}
}
set { customButton.Text = value; }
}
[Browsable(true), Description("Determines the appearance of the control when a user moves the mouse over the control and clicks."), Category("Button")]
[DisplayName("FlatStyle")]
[DefaultValue(FlatStyle.Flat)]
public FlatStyle ButtonFlatStyle
{
get
{
if (customButton == null)
{
return GetDefaultValue<FlatStyle>(this, "ButtonFlatStyle");
}
else
{
return customButton.FlatStyle;
}
}
set { customButton.FlatStyle = value; }
}
[Browsable(true), Description("The alignment of the text that will be displayed on the control."), Category("Button")]
[DisplayName("TextAlign")]
[DefaultValue(System.Drawing.ContentAlignment.MiddleCenter)]
public System.Drawing.ContentAlignment ButtonTextAlign
{
get
{
if (customButton == null)
{
return GetDefaultValue<System.Drawing.ContentAlignment>(this, "ButtonTextAlign");
}
else
{
return customButton.TextAlign;
}
}
set { customButton.TextAlign = value; }
}
[Browsable(true), Description("Specifies the relative location of the image to the text on the button."), Category("Button")]
[DisplayName("TextImageRelation")]
[DefaultValue(TextImageRelation.Overlay)]
public TextImageRelation ButtonTextImageRelation
{
get
{
if (customButton == null)
{
return GetDefaultValue<TextImageRelation>(this, "ButtonTextImageRelation");
}
else
{
return customButton.TextImageRelation;
}
}
set { customButton.TextImageRelation = value; }
}
[Browsable(true), Description("The button image associated with the control"), Category("Button")]
[DisplayName("Image")]
public Image ButtonImage
{
get
{
if (customButton == null)
{
return GetDefaultValue<Image>(this, "ButtonImage");
}
else
{
return customButton.Image;
}
}
set { customButton.Image = value; }
}
[Browsable(true), Description("Indicates if the button associated with the control is always visable"), Category("Button")]
[DisplayName("ButtonAlwaysVisible")]
[DefaultValue(false)]
public bool ButtonAlwaysVisible { get; set; }
static T GetDefaultValue<T>(object obj, string propertyName)
{
if (obj == null) return default(T);
var prop = obj.GetType().GetProperty(propertyName);
if (prop == null) return default(T);
var attr = prop.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attr.Length != 1) return default(T);
return (T)((DefaultValueAttribute)attr[0]).Value;
}
public ComboBoxWithButton()
{
CustomButton.Click += CustomButton_Click;
}
[DefaultValue(8)]
protected internal int EditControlOffset { get; set; } = 4;
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
UpdateControlsPosition();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case NativeMethods.WM_WINDOWPOSCHANGED:
UpdateControlsPosition();
break;
case NativeMethods.WM_DESTROY:
if (customButton != null)
{
customButton.Click -= CustomButton_Click;
customButton.Dispose();
}
break;
}
}
private void UpdateControlsPosition()
{
if (customButton != null)
{
SuspendLayout();
Rectangle arrowRect = NativeMethods.GetComboBoxInfoInternal(Handle, out Rectangle editRect, out IntPtr editHwnd);
if (arrowRect.IsEmpty || editRect.IsEmpty) return;
// Same size as the Arrow Button: change as required
DROPDOWNBUTTON_WIDTH = arrowRect.Width;
customButton.Size = arrowRect.Size;
customButton.Location = new Point(arrowRect.Left - customButton.Width - 1, 1);
editRect.Width = ClientSize.Width - customButton.Width * 2 - EditControlOffset;
NativeMethods.SetWindowPos(editHwnd, IntPtr.Zero, 0, 0, editRect.Width, editRect.Height, NativeMethods.SWP_Flags);
ResumeLayout(false);
}
}
private void CustomButton_Click(object sender, EventArgs e) => OnEditButtonClicked(e);
protected virtual void OnEditButtonClicked(EventArgs e)
{
ButtonClicked?.Invoke(this, e);
}
internal static Rectangle GetComboArrowBounds(Rectangle bounds)
{
return new Rectangle(bounds.Right - DROPDOWNBUTTON_WIDTH, bounds.Top, DROPDOWNBUTTON_WIDTH, bounds.Height);
}
internal static Rectangle GetComboButtonBounds(Rectangle bounds)
{
return new Rectangle(bounds.Right - BUTTON_WIDTH - BUTTON_WIDTH, bounds.Top, BUTTON_WIDTH, bounds.Height);
}
}
`
Here is the datagridviewcolumn code I have created so far.
`
<code>public class DataGridViewComboBoxWithButtonColumn : DataGridViewComboBoxColumn
private Button customButton;
public Button CustomButton
if (customButton == null)
customButton = new Button()
FlatStyle = ButtonFlatStyle,
TextAlign = ButtonTextAlign,
TextImageRelation = ButtonTextImageRelation
customButton.FlatAppearance.BorderSize = 0;
internal set { customButton = value; }
[Browsable(true), Description("Occurs when the component is clicked."), Category("Button")]
public event EventHandler<EventArgs> ButtonClicked;
[Browsable(true), Description("The button text associated with the control"), Category("Button")]
if (customButton == null)
return GetDefaultValue<string>(this, "ButtonText");
return customButton.Text;
set { customButton.Text = value; }
[Browsable(true), Description("Determines the appearance of the control when a user moves the mouse over the control and clicks."), Category("Button")]
[DisplayName("FlatStyle")]
[DefaultValue(FlatStyle.Flat)]
public FlatStyle ButtonFlatStyle
if (customButton == null)
return GetDefaultValue<FlatStyle>(this, "ButtonFlatStyle");
return customButton.FlatStyle;
set { customButton.FlatStyle = value; }
[Browsable(true), Description("The alignment of the text that will be displayed on the control."), Category("Button")]
[DisplayName("TextAlign")]
[DefaultValue(System.Drawing.ContentAlignment.MiddleCenter)]
public System.Drawing.ContentAlignment ButtonTextAlign
if (customButton == null)
return GetDefaultValue<System.Drawing.ContentAlignment>(this, "ButtonTextAlign");
return customButton.TextAlign;
set { customButton.TextAlign = value; }
[Browsable(true), Description("Specifies the relative location of the image to the text on the button."), Category("Button")]
[DisplayName("TextImageRelation")]
[DefaultValue(TextImageRelation.Overlay)]
public TextImageRelation ButtonTextImageRelation
if (customButton == null)
return GetDefaultValue<TextImageRelation>(this, "ButtonTextImageRelation");
return customButton.TextImageRelation;
set { customButton.TextImageRelation = value; }
[Browsable(true), Description("The button image associated with the control"), Category("Button")]
if (customButton == null)
return GetDefaultValue<Image>(this, "ButtonImage");
return customButton.Image;
set { customButton.Image = value; }
[Browsable(true), Description("Indicates if the button associated with the control is always visable"), Category("Button")]
[DisplayName("ButtonAlwaysVisible")]
public bool ButtonAlwaysVisible { get; set; }
public DataGridViewComboBoxWithButtonColumn() : base()
DataGridViewComboBoxWithButtonCell template = new DataGridViewComboBoxWithButtonCell();
template.CustomButton = CustomButton;
template.ButtonClicked += ButtonClicked;
this.CellTemplate = template;
public override DataGridViewCell CellTemplate
return base.CellTemplate;
if (value != null && !(value.GetType().IsAssignableFrom(typeof(DataGridViewComboBoxWithButtonCell))))
throw new InvalidCastException("Must be a DataGridViewComboBoxWithButtonCell");
base.CellTemplate = value;
public override object Clone()
var clone = (DataGridViewComboBoxWithButtonColumn)base.Clone();
clone.CustomButton = CustomButton;
clone.ButtonAlwaysVisible = ButtonAlwaysVisible;
static T GetDefaultValue<T>(object obj, string propertyName)
if (obj == null) return default(T);
var prop = obj.GetType().GetProperty(propertyName);
if (prop == null) return default(T);
var attr = prop.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attr.Length != 1) return default(T);
return (T)((DefaultValueAttribute)attr[0]).Value;
<code>public class DataGridViewComboBoxWithButtonColumn : DataGridViewComboBoxColumn
{
private Button customButton;
public Button CustomButton
{
get
{
if (customButton == null)
{
customButton = new Button()
{
Text = ButtonText,
FlatStyle = ButtonFlatStyle,
TextAlign = ButtonTextAlign,
TextImageRelation = ButtonTextImageRelation
};
customButton.FlatAppearance.BorderSize = 0;
}
return customButton;
}
internal set { customButton = value; }
}
[Browsable(true), Description("Occurs when the component is clicked."), Category("Button")]
[DisplayName("Click")]
public event EventHandler<EventArgs> ButtonClicked;
[Browsable(true), Description("The button text associated with the control"), Category("Button")]
[DisplayName("Text")]
[DefaultValue("?")]
public string ButtonText
{
get
{
if (customButton == null)
{
return GetDefaultValue<string>(this, "ButtonText");
}
else
{
return customButton.Text;
}
}
set { customButton.Text = value; }
}
[Browsable(true), Description("Determines the appearance of the control when a user moves the mouse over the control and clicks."), Category("Button")]
[DisplayName("FlatStyle")]
[DefaultValue(FlatStyle.Flat)]
public FlatStyle ButtonFlatStyle
{
get
{
if (customButton == null)
{
return GetDefaultValue<FlatStyle>(this, "ButtonFlatStyle");
}
else
{
return customButton.FlatStyle;
}
}
set { customButton.FlatStyle = value; }
}
[Browsable(true), Description("The alignment of the text that will be displayed on the control."), Category("Button")]
[DisplayName("TextAlign")]
[DefaultValue(System.Drawing.ContentAlignment.MiddleCenter)]
public System.Drawing.ContentAlignment ButtonTextAlign
{
get
{
if (customButton == null)
{
return GetDefaultValue<System.Drawing.ContentAlignment>(this, "ButtonTextAlign");
}
else
{
return customButton.TextAlign;
}
}
set { customButton.TextAlign = value; }
}
[Browsable(true), Description("Specifies the relative location of the image to the text on the button."), Category("Button")]
[DisplayName("TextImageRelation")]
[DefaultValue(TextImageRelation.Overlay)]
public TextImageRelation ButtonTextImageRelation
{
get
{
if (customButton == null)
{
return GetDefaultValue<TextImageRelation>(this, "ButtonTextImageRelation");
}
else
{
return customButton.TextImageRelation;
}
}
set { customButton.TextImageRelation = value; }
}
[Browsable(true), Description("The button image associated with the control"), Category("Button")]
[DisplayName("Image")]
public Image ButtonImage
{
get
{
if (customButton == null)
{
return GetDefaultValue<Image>(this, "ButtonImage");
}
else
{
return customButton.Image;
}
}
set { customButton.Image = value; }
}
[Browsable(true), Description("Indicates if the button associated with the control is always visable"), Category("Button")]
[DisplayName("ButtonAlwaysVisible")]
[DefaultValue(false)]
public bool ButtonAlwaysVisible { get; set; }
public DataGridViewComboBoxWithButtonColumn() : base()
{
DataGridViewComboBoxWithButtonCell template = new DataGridViewComboBoxWithButtonCell();
template.CustomButton = CustomButton;
template.ButtonClicked += ButtonClicked;
this.CellTemplate = template;
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
if (value != null && !(value.GetType().IsAssignableFrom(typeof(DataGridViewComboBoxWithButtonCell))))
{
throw new InvalidCastException("Must be a DataGridViewComboBoxWithButtonCell");
}
base.CellTemplate = value;
}
}
public override object Clone()
{
var clone = (DataGridViewComboBoxWithButtonColumn)base.Clone();
clone.CustomButton = CustomButton;
clone.ButtonAlwaysVisible = ButtonAlwaysVisible;
return clone;
}
static T GetDefaultValue<T>(object obj, string propertyName)
{
if (obj == null) return default(T);
var prop = obj.GetType().GetProperty(propertyName);
if (prop == null) return default(T);
var attr = prop.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attr.Length != 1) return default(T);
return (T)((DefaultValueAttribute)attr[0]).Value;
}
}
</code>
public class DataGridViewComboBoxWithButtonColumn : DataGridViewComboBoxColumn
{
private Button customButton;
public Button CustomButton
{
get
{
if (customButton == null)
{
customButton = new Button()
{
Text = ButtonText,
FlatStyle = ButtonFlatStyle,
TextAlign = ButtonTextAlign,
TextImageRelation = ButtonTextImageRelation
};
customButton.FlatAppearance.BorderSize = 0;
}
return customButton;
}
internal set { customButton = value; }
}
[Browsable(true), Description("Occurs when the component is clicked."), Category("Button")]
[DisplayName("Click")]
public event EventHandler<EventArgs> ButtonClicked;
[Browsable(true), Description("The button text associated with the control"), Category("Button")]
[DisplayName("Text")]
[DefaultValue("?")]
public string ButtonText
{
get
{
if (customButton == null)
{
return GetDefaultValue<string>(this, "ButtonText");
}
else
{
return customButton.Text;
}
}
set { customButton.Text = value; }
}
[Browsable(true), Description("Determines the appearance of the control when a user moves the mouse over the control and clicks."), Category("Button")]
[DisplayName("FlatStyle")]
[DefaultValue(FlatStyle.Flat)]
public FlatStyle ButtonFlatStyle
{
get
{
if (customButton == null)
{
return GetDefaultValue<FlatStyle>(this, "ButtonFlatStyle");
}
else
{
return customButton.FlatStyle;
}
}
set { customButton.FlatStyle = value; }
}
[Browsable(true), Description("The alignment of the text that will be displayed on the control."), Category("Button")]
[DisplayName("TextAlign")]
[DefaultValue(System.Drawing.ContentAlignment.MiddleCenter)]
public System.Drawing.ContentAlignment ButtonTextAlign
{
get
{
if (customButton == null)
{
return GetDefaultValue<System.Drawing.ContentAlignment>(this, "ButtonTextAlign");
}
else
{
return customButton.TextAlign;
}
}
set { customButton.TextAlign = value; }
}
[Browsable(true), Description("Specifies the relative location of the image to the text on the button."), Category("Button")]
[DisplayName("TextImageRelation")]
[DefaultValue(TextImageRelation.Overlay)]
public TextImageRelation ButtonTextImageRelation
{
get
{
if (customButton == null)
{
return GetDefaultValue<TextImageRelation>(this, "ButtonTextImageRelation");
}
else
{
return customButton.TextImageRelation;
}
}
set { customButton.TextImageRelation = value; }
}
[Browsable(true), Description("The button image associated with the control"), Category("Button")]
[DisplayName("Image")]
public Image ButtonImage
{
get
{
if (customButton == null)
{
return GetDefaultValue<Image>(this, "ButtonImage");
}
else
{
return customButton.Image;
}
}
set { customButton.Image = value; }
}
[Browsable(true), Description("Indicates if the button associated with the control is always visable"), Category("Button")]
[DisplayName("ButtonAlwaysVisible")]
[DefaultValue(false)]
public bool ButtonAlwaysVisible { get; set; }
public DataGridViewComboBoxWithButtonColumn() : base()
{
DataGridViewComboBoxWithButtonCell template = new DataGridViewComboBoxWithButtonCell();
template.CustomButton = CustomButton;
template.ButtonClicked += ButtonClicked;
this.CellTemplate = template;
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
if (value != null && !(value.GetType().IsAssignableFrom(typeof(DataGridViewComboBoxWithButtonCell))))
{
throw new InvalidCastException("Must be a DataGridViewComboBoxWithButtonCell");
}
base.CellTemplate = value;
}
}
public override object Clone()
{
var clone = (DataGridViewComboBoxWithButtonColumn)base.Clone();
clone.CustomButton = CustomButton;
clone.ButtonAlwaysVisible = ButtonAlwaysVisible;
return clone;
}
static T GetDefaultValue<T>(object obj, string propertyName)
{
if (obj == null) return default(T);
var prop = obj.GetType().GetProperty(propertyName);
if (prop == null) return default(T);
var attr = prop.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attr.Length != 1) return default(T);
return (T)((DefaultValueAttribute)attr[0]).Value;
}
}
`
<code>public class DataGridViewComboBoxWithButtonCell : DataGridViewComboBoxCell
private static int DROPDOWNBUTTON_WIDTH = 17;
private static int BUTTON_WIDTH = 17;
private Button customButton;
public Button CustomButton
if (customButton == null)
customButton = new Button();
customButton.SizeChanged += CustomButton_SizeChanged;
customButton.MouseDown += CustomButton_MouseDown;
customButton.MouseEnter += CustomButton_MouseEnter;
customButton.MouseLeave += CustomButton_MouseLeave;
customButton.MouseHover += CustomButton_MouseHover;
[Browsable(true), Description("Occurs when the component is clicked."), Category("Button")]
public event EventHandler<EventArgs> ButtonClicked;
private void CustomButton_SizeChanged(object sender, EventArgs e)
BUTTON_WIDTH = customButton.Width;
public DataGridViewComboBoxWithButtonCell() : base()
private void CustomButton_MouseHover(object sender, EventArgs e)
CustomButtonState = PushButtonState.Hot;
private void CustomButton_MouseLeave(object sender, EventArgs e)
CustomButtonState = PushButtonState.Normal;
private void CustomButton_MouseEnter(object sender, EventArgs e)
CustomButtonState = PushButtonState.Hot;
private void CustomButton_MouseDown(object sender, MouseEventArgs e)
CustomButtonState = PushButtonState.Pressed;
protected override void Paint(Graphics graphics, Rectangle clipBounds, 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);
BeforePaintContent(graphics, cellBounds, cellState, cellStyle, paintParts);
if (paintParts.HasFlag(DataGridViewPaintParts.ContentForeground))
Rectangle contentBounds = cellBounds;
contentBounds.Width -= DROPDOWNBUTTON_WIDTH;
TextFormatFlags flags = TextFormatFlags.NoPrefix | TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.LeftAndRightPadding | TextFormatFlags.PreserveGraphicsClipping;
TextRenderer.DrawText(graphics, Convert.ToString(formattedValue), cellStyle.Font, contentBounds, cellStyle.ForeColor, flags);
AfterPaintContent(graphics, clipBounds, cellBounds, rowIndex, cellStyle, advancedBorderStyle, paintParts);
protected void BeforePaintContent(Graphics graphics, Rectangle cellBounds, DataGridViewElementStates cellState, DataGridViewCellStyle cellStyle, DataGridViewPaintParts paintParts)
if (paintParts.HasFlag(DataGridViewPaintParts.Background))
using (Brush brush = new SolidBrush(cellStyle.BackColor))
graphics.FillRectangle(brush, cellBounds);
if (paintParts.HasFlag(DataGridViewPaintParts.SelectionBackground) && cellState.HasFlag(DataGridViewElementStates.Selected))
using (Brush brush = new SolidBrush(cellStyle.SelectionBackColor))
graphics.FillRectangle(brush, cellBounds);
if (paintParts.HasFlag(DataGridViewPaintParts.ContentBackground))
ButtonState legacyState = ButtonState.Normal;
if ((DataGridView.Site == null) || !DataGridView.Site.DesignMode)
if (cellState.HasFlag(DataGridViewElementStates.ReadOnly))
state = ComboBoxState.Disabled;
legacyState = ButtonState.Inactive;
else if (cellBounds.Contains(DataGridView.PointToClient(DataGridView.MousePosition)))
if (DataGridView.MouseButtons.HasFlag(MouseButtons.Left))
state = ComboBoxState.Pressed;
legacyState = ButtonState.Pushed;
state = ComboBoxState.Hot;
Rectangle comboBounds = cellBounds;
DrawComboBox(graphics, comboBounds);
protected void AfterPaintContent(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
if (paintParts.HasFlag(DataGridViewPaintParts.ErrorIcon))
base.PaintErrorIcon(graphics, clipBounds, cellBounds, GetErrorText(rowIndex));
if (paintParts.HasFlag(DataGridViewPaintParts.Border))
base.PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
if (paintParts.HasFlag(DataGridViewPaintParts.Focus) && (DataGridView.CurrentCell == this))
Rectangle focusBounds = cellBounds;
ControlPaint.DrawFocusRectangle(graphics, focusBounds);
internal static Rectangle GetComboArrowBounds(Rectangle bounds)
return new Rectangle(bounds.Right - DROPDOWNBUTTON_WIDTH, bounds.Top, DROPDOWNBUTTON_WIDTH, bounds.Height);
internal static Rectangle GetComboButtonBounds(Rectangle bounds)
return new Rectangle(bounds.Right - BUTTON_WIDTH - BUTTON_WIDTH, bounds.Top, BUTTON_WIDTH, bounds.Height);
internal static PushButtonState CustomButtonState
} = PushButtonState.Normal;
internal ComboBoxState state = ComboBoxState.Normal;
private void DrawComboBox(Graphics graphics, Rectangle bounds)
Rectangle comboBounds = bounds;
Rectangle ButtonBounds = GetComboButtonBounds(comboBounds);
Rectangle ArrowBounds = GetComboArrowBounds(comboBounds);
comboBounds.Inflate(1, 1);
if (ButtonBounds.X >= (bounds.Width + bounds.X))
ButtonBounds.X = (bounds.Width + bounds.X) - (ButtonBounds.Width + ArrowBounds.Width);
ButtonRenderer.DrawButton(graphics, ButtonBounds, CustomButton.Text, CustomButton.Font, TextFormatFlags.Default, CustomButton.CanFocus, CustomButtonState);
if (ArrowBounds.X >= (bounds.Width + bounds.X))
ArrowBounds.X = (bounds.Width + bounds.X) - ArrowBounds.Width;
Rectangle buttonClip = ArrowBounds;
buttonClip.Inflate(-2, -2);
using (Region oldClip = graphics.Clip.Clone())
graphics.SetClip(buttonClip, System.Drawing.Drawing2D.CombineMode.Intersect);
ComboBoxRenderer.DrawDropDownButton(graphics, ArrowBounds, state);
graphics.SetClip(oldClip, System.Drawing.Drawing2D.CombineMode.Replace);
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
ComboBoxWithButton comboBox = base.DataGridView.EditingControl as ComboBoxWithButton;
comboBox.DropDownStyle = ComboBoxStyle.DropDown;
comboBox.AutoCompleteSource = AutoCompleteSource.ListItems;
comboBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
public override Type EditType
return typeof(ComboBoxWithButtonEditingControl);
public override Type ValueType
public override object Clone()
var clone = (DataGridViewComboBoxWithButtonCell)base.Clone();
<code>public class DataGridViewComboBoxWithButtonCell : DataGridViewComboBoxCell
{
private static int DROPDOWNBUTTON_WIDTH = 17;
private static int BUTTON_WIDTH = 17;
private Button customButton;
public Button CustomButton
{
get
{
if (customButton == null)
{
customButton = new Button();
}
return customButton;
}
internal set
{
customButton = value;
customButton.SizeChanged += CustomButton_SizeChanged;
customButton.MouseDown += CustomButton_MouseDown;
customButton.MouseEnter += CustomButton_MouseEnter;
customButton.MouseLeave += CustomButton_MouseLeave;
customButton.MouseHover += CustomButton_MouseHover;
}
}
[Browsable(true), Description("Occurs when the component is clicked."), Category("Button")]
[DisplayName("Click")]
public event EventHandler<EventArgs> ButtonClicked;
private void CustomButton_SizeChanged(object sender, EventArgs e)
{
BUTTON_WIDTH = customButton.Width;
}
public DataGridViewComboBoxWithButtonCell() : base()
{
}
private void CustomButton_MouseHover(object sender, EventArgs e)
{
CustomButtonState = PushButtonState.Hot;
}
private void CustomButton_MouseLeave(object sender, EventArgs e)
{
CustomButtonState = PushButtonState.Normal;
}
private void CustomButton_MouseEnter(object sender, EventArgs e)
{
CustomButtonState = PushButtonState.Hot;
}
private void CustomButton_MouseDown(object sender, MouseEventArgs e)
{
CustomButtonState = PushButtonState.Pressed;
}
protected override void Paint(Graphics graphics, Rectangle clipBounds, 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);
BeforePaintContent(graphics, cellBounds, cellState, cellStyle, paintParts);
if (paintParts.HasFlag(DataGridViewPaintParts.ContentForeground))
{
Rectangle contentBounds = cellBounds;
contentBounds.Width -= DROPDOWNBUTTON_WIDTH;
TextFormatFlags flags = TextFormatFlags.NoPrefix | TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.LeftAndRightPadding | TextFormatFlags.PreserveGraphicsClipping;
TextRenderer.DrawText(graphics, Convert.ToString(formattedValue), cellStyle.Font, contentBounds, cellStyle.ForeColor, flags);
}
AfterPaintContent(graphics, clipBounds, cellBounds, rowIndex, cellStyle, advancedBorderStyle, paintParts);
}
protected void BeforePaintContent(Graphics graphics, Rectangle cellBounds, DataGridViewElementStates cellState, DataGridViewCellStyle cellStyle, DataGridViewPaintParts paintParts)
{
if (paintParts.HasFlag(DataGridViewPaintParts.Background))
{
using (Brush brush = new SolidBrush(cellStyle.BackColor))
{
graphics.FillRectangle(brush, cellBounds);
}
}
if (paintParts.HasFlag(DataGridViewPaintParts.SelectionBackground) && cellState.HasFlag(DataGridViewElementStates.Selected))
{
using (Brush brush = new SolidBrush(cellStyle.SelectionBackColor))
{
graphics.FillRectangle(brush, cellBounds);
}
}
if (paintParts.HasFlag(DataGridViewPaintParts.ContentBackground))
{
ButtonState legacyState = ButtonState.Normal;
if ((DataGridView.Site == null) || !DataGridView.Site.DesignMode)
{
if (cellState.HasFlag(DataGridViewElementStates.ReadOnly))
{
state = ComboBoxState.Disabled;
legacyState = ButtonState.Inactive;
}
else if (cellBounds.Contains(DataGridView.PointToClient(DataGridView.MousePosition)))
{
if (DataGridView.MouseButtons.HasFlag(MouseButtons.Left))
{
state = ComboBoxState.Pressed;
legacyState = ButtonState.Pushed;
}
else
{
state = ComboBoxState.Hot;
}
}
}
Rectangle comboBounds = cellBounds;
comboBounds.Width--;
DrawComboBox(graphics, comboBounds);
}
}
protected void AfterPaintContent(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
if (paintParts.HasFlag(DataGridViewPaintParts.ErrorIcon))
{
base.PaintErrorIcon(graphics, clipBounds, cellBounds, GetErrorText(rowIndex));
}
if (paintParts.HasFlag(DataGridViewPaintParts.Border))
{
base.PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
}
if (paintParts.HasFlag(DataGridViewPaintParts.Focus) && (DataGridView.CurrentCell == this))
{
Rectangle focusBounds = cellBounds;
focusBounds.Width--;
focusBounds.Height--;
ControlPaint.DrawFocusRectangle(graphics, focusBounds);
}
}
internal static Rectangle GetComboArrowBounds(Rectangle bounds)
{
return new Rectangle(bounds.Right - DROPDOWNBUTTON_WIDTH, bounds.Top, DROPDOWNBUTTON_WIDTH, bounds.Height);
}
internal static Rectangle GetComboButtonBounds(Rectangle bounds)
{
return new Rectangle(bounds.Right - BUTTON_WIDTH - BUTTON_WIDTH, bounds.Top, BUTTON_WIDTH, bounds.Height);
}
internal static PushButtonState CustomButtonState
{
get; private set;
} = PushButtonState.Normal;
internal ComboBoxState state = ComboBoxState.Normal;
private void DrawComboBox(Graphics graphics, Rectangle bounds)
{
Rectangle comboBounds = bounds;
Rectangle ButtonBounds = GetComboButtonBounds(comboBounds);
Rectangle ArrowBounds = GetComboArrowBounds(comboBounds);
comboBounds.Inflate(1, 1);
if (ButtonBounds.X >= (bounds.Width + bounds.X))
{
ButtonBounds.X = (bounds.Width + bounds.X) - (ButtonBounds.Width + ArrowBounds.Width);
}
ButtonRenderer.DrawButton(graphics, ButtonBounds, CustomButton.Text, CustomButton.Font, TextFormatFlags.Default, CustomButton.CanFocus, CustomButtonState);
if (ArrowBounds.X >= (bounds.Width + bounds.X))
{
ArrowBounds.X = (bounds.Width + bounds.X) - ArrowBounds.Width;
}
Rectangle buttonClip = ArrowBounds;
buttonClip.Inflate(-2, -2);
using (Region oldClip = graphics.Clip.Clone())
{
graphics.SetClip(buttonClip, System.Drawing.Drawing2D.CombineMode.Intersect);
ComboBoxRenderer.DrawDropDownButton(graphics, ArrowBounds, state);
graphics.SetClip(oldClip, System.Drawing.Drawing2D.CombineMode.Replace);
}
}
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
ComboBoxWithButton comboBox = base.DataGridView.EditingControl as ComboBoxWithButton;
if (comboBox != null)
{
comboBox.BeginUpdate();
comboBox.DropDownStyle = ComboBoxStyle.DropDown;
comboBox.AutoCompleteSource = AutoCompleteSource.ListItems;
comboBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
comboBox.EndUpdate();
}
}
public override Type EditType
{
get
{
return typeof(ComboBoxWithButtonEditingControl);
}
}
public override Type ValueType
{
get
{
return base.ValueType;
}
}
public override object Clone()
{
var clone = (DataGridViewComboBoxWithButtonCell)base.Clone();
return clone;
}
}
</code>
public class DataGridViewComboBoxWithButtonCell : DataGridViewComboBoxCell
{
private static int DROPDOWNBUTTON_WIDTH = 17;
private static int BUTTON_WIDTH = 17;
private Button customButton;
public Button CustomButton
{
get
{
if (customButton == null)
{
customButton = new Button();
}
return customButton;
}
internal set
{
customButton = value;
customButton.SizeChanged += CustomButton_SizeChanged;
customButton.MouseDown += CustomButton_MouseDown;
customButton.MouseEnter += CustomButton_MouseEnter;
customButton.MouseLeave += CustomButton_MouseLeave;
customButton.MouseHover += CustomButton_MouseHover;
}
}
[Browsable(true), Description("Occurs when the component is clicked."), Category("Button")]
[DisplayName("Click")]
public event EventHandler<EventArgs> ButtonClicked;
private void CustomButton_SizeChanged(object sender, EventArgs e)
{
BUTTON_WIDTH = customButton.Width;
}
public DataGridViewComboBoxWithButtonCell() : base()
{
}
private void CustomButton_MouseHover(object sender, EventArgs e)
{
CustomButtonState = PushButtonState.Hot;
}
private void CustomButton_MouseLeave(object sender, EventArgs e)
{
CustomButtonState = PushButtonState.Normal;
}
private void CustomButton_MouseEnter(object sender, EventArgs e)
{
CustomButtonState = PushButtonState.Hot;
}
private void CustomButton_MouseDown(object sender, MouseEventArgs e)
{
CustomButtonState = PushButtonState.Pressed;
}
protected override void Paint(Graphics graphics, Rectangle clipBounds, 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);
BeforePaintContent(graphics, cellBounds, cellState, cellStyle, paintParts);
if (paintParts.HasFlag(DataGridViewPaintParts.ContentForeground))
{
Rectangle contentBounds = cellBounds;
contentBounds.Width -= DROPDOWNBUTTON_WIDTH;
TextFormatFlags flags = TextFormatFlags.NoPrefix | TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.LeftAndRightPadding | TextFormatFlags.PreserveGraphicsClipping;
TextRenderer.DrawText(graphics, Convert.ToString(formattedValue), cellStyle.Font, contentBounds, cellStyle.ForeColor, flags);
}
AfterPaintContent(graphics, clipBounds, cellBounds, rowIndex, cellStyle, advancedBorderStyle, paintParts);
}
protected void BeforePaintContent(Graphics graphics, Rectangle cellBounds, DataGridViewElementStates cellState, DataGridViewCellStyle cellStyle, DataGridViewPaintParts paintParts)
{
if (paintParts.HasFlag(DataGridViewPaintParts.Background))
{
using (Brush brush = new SolidBrush(cellStyle.BackColor))
{
graphics.FillRectangle(brush, cellBounds);
}
}
if (paintParts.HasFlag(DataGridViewPaintParts.SelectionBackground) && cellState.HasFlag(DataGridViewElementStates.Selected))
{
using (Brush brush = new SolidBrush(cellStyle.SelectionBackColor))
{
graphics.FillRectangle(brush, cellBounds);
}
}
if (paintParts.HasFlag(DataGridViewPaintParts.ContentBackground))
{
ButtonState legacyState = ButtonState.Normal;
if ((DataGridView.Site == null) || !DataGridView.Site.DesignMode)
{
if (cellState.HasFlag(DataGridViewElementStates.ReadOnly))
{
state = ComboBoxState.Disabled;
legacyState = ButtonState.Inactive;
}
else if (cellBounds.Contains(DataGridView.PointToClient(DataGridView.MousePosition)))
{
if (DataGridView.MouseButtons.HasFlag(MouseButtons.Left))
{
state = ComboBoxState.Pressed;
legacyState = ButtonState.Pushed;
}
else
{
state = ComboBoxState.Hot;
}
}
}
Rectangle comboBounds = cellBounds;
comboBounds.Width--;
DrawComboBox(graphics, comboBounds);
}
}
protected void AfterPaintContent(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
if (paintParts.HasFlag(DataGridViewPaintParts.ErrorIcon))
{
base.PaintErrorIcon(graphics, clipBounds, cellBounds, GetErrorText(rowIndex));
}
if (paintParts.HasFlag(DataGridViewPaintParts.Border))
{
base.PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
}
if (paintParts.HasFlag(DataGridViewPaintParts.Focus) && (DataGridView.CurrentCell == this))
{
Rectangle focusBounds = cellBounds;
focusBounds.Width--;
focusBounds.Height--;
ControlPaint.DrawFocusRectangle(graphics, focusBounds);
}
}
internal static Rectangle GetComboArrowBounds(Rectangle bounds)
{
return new Rectangle(bounds.Right - DROPDOWNBUTTON_WIDTH, bounds.Top, DROPDOWNBUTTON_WIDTH, bounds.Height);
}
internal static Rectangle GetComboButtonBounds(Rectangle bounds)
{
return new Rectangle(bounds.Right - BUTTON_WIDTH - BUTTON_WIDTH, bounds.Top, BUTTON_WIDTH, bounds.Height);
}
internal static PushButtonState CustomButtonState
{
get; private set;
} = PushButtonState.Normal;
internal ComboBoxState state = ComboBoxState.Normal;
private void DrawComboBox(Graphics graphics, Rectangle bounds)
{
Rectangle comboBounds = bounds;
Rectangle ButtonBounds = GetComboButtonBounds(comboBounds);
Rectangle ArrowBounds = GetComboArrowBounds(comboBounds);
comboBounds.Inflate(1, 1);
if (ButtonBounds.X >= (bounds.Width + bounds.X))
{
ButtonBounds.X = (bounds.Width + bounds.X) - (ButtonBounds.Width + ArrowBounds.Width);
}
ButtonRenderer.DrawButton(graphics, ButtonBounds, CustomButton.Text, CustomButton.Font, TextFormatFlags.Default, CustomButton.CanFocus, CustomButtonState);
if (ArrowBounds.X >= (bounds.Width + bounds.X))
{
ArrowBounds.X = (bounds.Width + bounds.X) - ArrowBounds.Width;
}
Rectangle buttonClip = ArrowBounds;
buttonClip.Inflate(-2, -2);
using (Region oldClip = graphics.Clip.Clone())
{
graphics.SetClip(buttonClip, System.Drawing.Drawing2D.CombineMode.Intersect);
ComboBoxRenderer.DrawDropDownButton(graphics, ArrowBounds, state);
graphics.SetClip(oldClip, System.Drawing.Drawing2D.CombineMode.Replace);
}
}
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
ComboBoxWithButton comboBox = base.DataGridView.EditingControl as ComboBoxWithButton;
if (comboBox != null)
{
comboBox.BeginUpdate();
comboBox.DropDownStyle = ComboBoxStyle.DropDown;
comboBox.AutoCompleteSource = AutoCompleteSource.ListItems;
comboBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
comboBox.EndUpdate();
}
}
public override Type EditType
{
get
{
return typeof(ComboBoxWithButtonEditingControl);
}
}
public override Type ValueType
{
get
{
return base.ValueType;
}
}
public override object Clone()
{
var clone = (DataGridViewComboBoxWithButtonCell)base.Clone();
return clone;
}
}
`
<code>internal class ComboBoxWithButtonEditingControl : ComboBoxWithButton, IDataGridViewEditingControl
private DataGridView dataGridView;
private bool valueChanged;
public virtual DataGridView EditingControlDataGridView
public virtual object EditingControlFormattedValue
return GetEditingControlFormattedValue(DataGridViewDataErrorContexts.Formatting);
string text = value as string;
if (string.Compare(text, Text, ignoreCase: true, CultureInfo.CurrentCulture) != 0)
public virtual int EditingControlRowIndex
public virtual bool EditingControlValueChanged
public virtual Cursor EditingPanelCursor => Cursors.Default;
public virtual bool RepositionEditingControlOnValueChange => false;
public ComboBoxWithButtonEditingControl()
public virtual void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
Font = dataGridViewCellStyle.Font;
if (dataGridViewCellStyle.BackColor.A < byte.MaxValue)
Color backColor = (BackColor = Color.FromArgb(255, dataGridViewCellStyle.BackColor));
dataGridView.EditingPanel.BackColor = backColor;
BackColor = dataGridViewCellStyle.BackColor;
ForeColor = dataGridViewCellStyle.ForeColor;
public virtual bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
if ((keyData & Keys.KeyCode) == Keys.Down || (keyData & Keys.KeyCode) == Keys.Up || (base.DroppedDown && (keyData & Keys.KeyCode) == Keys.Escape) || (keyData & Keys.KeyCode) == Keys.Return)
return !dataGridViewWantsInputKey;
public virtual object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
public virtual void PrepareEditingControlForEdit(bool selectAll)
private void NotifyDataGridViewOfValueChange()
dataGridView.NotifyCurrentCellDirty(dirty: true);
protected override void OnSelectedIndexChanged(EventArgs e)
base.OnSelectedIndexChanged(e);
NotifyDataGridViewOfValueChange();
<code>internal class ComboBoxWithButtonEditingControl : ComboBoxWithButton, IDataGridViewEditingControl
{
private DataGridView dataGridView;
private bool valueChanged;
private int rowIndex;
public virtual DataGridView EditingControlDataGridView
{
get
{
return dataGridView;
}
set
{
dataGridView = value;
}
}
public virtual object EditingControlFormattedValue
{
get
{
return GetEditingControlFormattedValue(DataGridViewDataErrorContexts.Formatting);
}
set
{
string text = value as string;
if (text != null)
{
Text = text;
if (string.Compare(text, Text, ignoreCase: true, CultureInfo.CurrentCulture) != 0)
{
SelectedIndex = -1;
}
}
}
}
public virtual int EditingControlRowIndex
{
get
{
return rowIndex;
}
set
{
rowIndex = value;
}
}
public virtual bool EditingControlValueChanged
{
get
{
return valueChanged;
}
set
{
valueChanged = value;
}
}
public virtual Cursor EditingPanelCursor => Cursors.Default;
public virtual bool RepositionEditingControlOnValueChange => false;
public ComboBoxWithButtonEditingControl()
{
base.TabStop = false;
}
public virtual void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
Font = dataGridViewCellStyle.Font;
if (dataGridViewCellStyle.BackColor.A < byte.MaxValue)
{
Color backColor = (BackColor = Color.FromArgb(255, dataGridViewCellStyle.BackColor));
dataGridView.EditingPanel.BackColor = backColor;
}
else
{
BackColor = dataGridViewCellStyle.BackColor;
}
ForeColor = dataGridViewCellStyle.ForeColor;
}
public virtual bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
{
if ((keyData & Keys.KeyCode) == Keys.Down || (keyData & Keys.KeyCode) == Keys.Up || (base.DroppedDown && (keyData & Keys.KeyCode) == Keys.Escape) || (keyData & Keys.KeyCode) == Keys.Return)
{
return true;
}
return !dataGridViewWantsInputKey;
}
public virtual object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
{
return Text;
}
public virtual void PrepareEditingControlForEdit(bool selectAll)
{
if (selectAll)
{
SelectAll();
}
}
private void NotifyDataGridViewOfValueChange()
{
valueChanged = true;
dataGridView.NotifyCurrentCellDirty(dirty: true);
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
if (SelectedIndex != -1)
{
NotifyDataGridViewOfValueChange();
}
}
}`
</code>
internal class ComboBoxWithButtonEditingControl : ComboBoxWithButton, IDataGridViewEditingControl
{
private DataGridView dataGridView;
private bool valueChanged;
private int rowIndex;
public virtual DataGridView EditingControlDataGridView
{
get
{
return dataGridView;
}
set
{
dataGridView = value;
}
}
public virtual object EditingControlFormattedValue
{
get
{
return GetEditingControlFormattedValue(DataGridViewDataErrorContexts.Formatting);
}
set
{
string text = value as string;
if (text != null)
{
Text = text;
if (string.Compare(text, Text, ignoreCase: true, CultureInfo.CurrentCulture) != 0)
{
SelectedIndex = -1;
}
}
}
}
public virtual int EditingControlRowIndex
{
get
{
return rowIndex;
}
set
{
rowIndex = value;
}
}
public virtual bool EditingControlValueChanged
{
get
{
return valueChanged;
}
set
{
valueChanged = value;
}
}
public virtual Cursor EditingPanelCursor => Cursors.Default;
public virtual bool RepositionEditingControlOnValueChange => false;
public ComboBoxWithButtonEditingControl()
{
base.TabStop = false;
}
public virtual void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
Font = dataGridViewCellStyle.Font;
if (dataGridViewCellStyle.BackColor.A < byte.MaxValue)
{
Color backColor = (BackColor = Color.FromArgb(255, dataGridViewCellStyle.BackColor));
dataGridView.EditingPanel.BackColor = backColor;
}
else
{
BackColor = dataGridViewCellStyle.BackColor;
}
ForeColor = dataGridViewCellStyle.ForeColor;
}
public virtual bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
{
if ((keyData & Keys.KeyCode) == Keys.Down || (keyData & Keys.KeyCode) == Keys.Up || (base.DroppedDown && (keyData & Keys.KeyCode) == Keys.Escape) || (keyData & Keys.KeyCode) == Keys.Return)
{
return true;
}
return !dataGridViewWantsInputKey;
}
public virtual object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
{
return Text;
}
public virtual void PrepareEditingControlForEdit(bool selectAll)
{
if (selectAll)
{
SelectAll();
}
}
private void NotifyDataGridViewOfValueChange()
{
valueChanged = true;
dataGridView.NotifyCurrentCellDirty(dirty: true);
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
if (SelectedIndex != -1)
{
NotifyDataGridViewOfValueChange();
}
}
}`