Skip to content

Instantly share code, notes, and snippets.

@meitinger
Last active June 18, 2017 20:24
Show Gist options
  • Save meitinger/5071951a653af5714ee1 to your computer and use it in GitHub Desktop.
Save meitinger/5071951a653af5714ee1 to your computer and use it in GitHub Desktop.
[abandoned] Draft for data grid controls for all input types.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Linq.Expressions;
using System.Reflection;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public abstract class DataGridViewTypedColumn<T> : DataGridViewColumn where T : Control, IDataGridViewEditingControl, new()
{
private static readonly List<CellProperty> Properties = new List<CellProperty>();
protected abstract class CellProperty
{
internal CellProperty() { }
internal abstract void Clone(T source, T dest);
}
/// <summary>
/// Wrapper for a property to compensate for missing <c>ref</c>-functionality.
/// </summary>
/// <typeparam name="U">The property's type.</typeparam>
protected sealed class CellProperty<U> : CellProperty
{
private readonly PropertyInfo prop;
/// <summary>
/// Creates a new wrapper around a given property.
/// </summary>
/// <param name="prop">An expression in the form of <c>control => control.Property</c>.</param>
public CellProperty(Expression<Func<T, U>> prop)
{
// check that we got a non-indexed property with the proper declaring type
if (prop == null)
throw new ArgumentNullException("prop");
if
(
prop.Body.NodeType != ExpressionType.MemberAccess ||
((MemberExpression)prop.Body).Member.MemberType != MemberTypes.Property ||
((PropertyInfo)((MemberExpression)prop.Body).Member).GetIndexParameters().Length > 0 ||
!((PropertyInfo)((MemberExpression)prop.Body).Member).DeclaringType.IsAssignableFrom(typeof(T))
)
throw new ArgumentOutOfRangeException("prop");
// store the property info
this.prop = (PropertyInfo)((MemberExpression)prop.Body).Member;
Properties.Add(this);
}
internal override void Clone(T source, T dest)
{
this.prop.SetValue(dest, this.prop.GetValue(source, null), null);
}
private void SetValue(Cell cell, U value)
{
// set the value
this.prop.SetValue(cell.FormattingControl, value, null);
// propagate the changes if this isn't a shared row
if (cell.RowIndex != -1)
{
if (cell.EditingControl != null && cell.RowIndex == cell.EditingControl.EditingControlRowIndex)
this.prop.SetValue(cell.EditingControl, value, null);
cell.DataGridView.InvalidateCell(cell);
}
}
/// <summary>
/// Gets or sets the property of a given column's cell(s).
/// </summary>
/// <param name="column">The column whose property was queried or stored.</param>
/// <returns>The current template value.</returns>
/// <exception cref="System.InvalidOperationException">No template was set.</exception>
public U this[DataGridViewTypedColumn<T> column]
{
get
{
// ensure there's a template and get its value
var template = (Cell)column.CellTemplate;
if (template == null)
throw new InvalidOperationException();
return (U)this.prop.GetValue(template.FormattingControl, null);
}
set
{
// check if the template's value differs
var template = (Cell)column.CellTemplate;
if (template == null)
throw new InvalidOperationException();
if (!object.Equals((U)this.prop.GetValue(template.FormattingControl, null), value))
{
// update the template value
this.SetValue(template, value);
var gridView = column.DataGridView;
if (gridView != null)
{
// update all other cells and invalidate the column
var rows = gridView.Rows;
var count = rows.Count;
for (int i = 0; i < count; i++)
{
var cell = rows.SharedRow(i).Cells[column.Index] as Cell;
if (cell != null)
this.SetValue(cell, value);
}
gridView.InvalidateColumn(column.Index);
}
}
}
}
}
private class Cell : DataGridViewTextBoxCell
{
private bool formatToString = false;
public Cell()
{
// create a hidden formatting control
this.FormattingControl = new T();
this.FormattingControl.Visible = false;
}
public override object Clone()
{
// clone all properties
var clone = (Cell)base.Clone();
foreach (var prop in Properties)
prop.Clone(this.FormattingControl, clone.FormattingControl);
return clone;
}
internal T FormattingControl
{
get;
private set;
}
internal T EditingControl
{
get;
private set;
}
public override Type EditType
{
get { return typeof(T); }
}
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
// initialize and store the control
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
var editingControl = base.DataGridView.EditingControl as T;
foreach (var prop in Properties)
prop.Clone(this.FormattingControl, editingControl);
editingControl.EditingControlFormattedValue = initialFormattedValue;
this.EditingControl = editingControl;
}
public override void DetachEditingControl()
{
// detach and clear the control
base.DetachEditingControl();
this.EditingControl = null;
}
protected override Rectangle GetContentBounds(Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex)
{
// call the base method but use string formatting while doing so
if (this.formatToString)
return base.GetContentBounds(graphics, cellStyle, rowIndex);
this.formatToString = true;
try { return base.GetContentBounds(graphics, cellStyle, rowIndex); }
finally { this.formatToString = false; }
}
protected override Size GetPreferredSize(Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex, System.Drawing.Size constraintSize)
{
// call the base method but use string formatting while doing so
if (this.formatToString)
return base.GetPreferredSize(graphics, cellStyle, rowIndex, constraintSize);
this.formatToString = true;
try { return base.GetPreferredSize(graphics, cellStyle, rowIndex, constraintSize); }
finally { this.formatToString = false; }
}
protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
{
// convert the DBNull to null and optionally the value to string
var formattedValue = value == DBNull.Value ? null : value;
if (this.formatToString)
{
this.FormattingControl.EditingControlFormattedValue = formattedValue;
formattedValue = this.FormattingControl.Text;
}
return formattedValue;
}
public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
{
// convert null to DBNull
return formattedValue ?? DBNull.Value;
}
protected override void OnDataGridViewChanged()
{
// set the formatting control's parent and ensure its handle gets created
base.OnDataGridViewChanged();
this.FormattingControl.Parent = base.DataGridView;
this.FormattingControl.Visible = true;
this.FormattingControl.Visible = false;
}
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)
{
// call the base method with a string value
this.FormattingControl.EditingControlFormattedValue = formattedValue;
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, this.FormattingControl.Text, errorText, cellStyle, advancedBorderStyle, paintParts);
}
}
protected DataGridViewTypedColumn() : base(new Cell()) { }
public override DataGridViewCell CellTemplate
{
get { return base.CellTemplate; }
set
{
// ensure a proper template class
if (value != null && !(value is Cell))
throw new InvalidCastException();
base.CellTemplate = value;
}
}
}
[ToolboxBitmap(typeof(DateTimePicker), "DateTimePicker.bmp")]
public class DataGridViewDateTimePickerColumn : DataGridViewTypedColumn<DataGridViewDataTimePickerEditingControl>
{
private static readonly CellProperty<DateTimePickerFormat> FormatProperty = new CellProperty<DateTimePickerFormat>(t => t.Format);
private static readonly CellProperty<string> CustomFormatProperty = new CellProperty<string>(t => t.CustomFormat);
/// <summary>
/// Gets or sets the format of the date and time displayed in the cell.
/// </summary>
[DefaultValue(DateTimePickerFormat.Short)]
public DateTimePickerFormat Format
{
get { return FormatProperty[this]; }
set { FormatProperty[this] = value; }
}
/// <summary>
/// Gets or sets the custom date/time format string.
/// </summary>
[DefaultValue((string)null), Localizable(true)]
public string CustomFormat
{
get { return CustomFormatProperty[this]; }
set { CustomFormatProperty[this] = value; }
}
}
public class DataGridViewDataTimePickerEditingControl : DateTimePicker, IDataGridViewEditingControl
{
private static readonly DateTime SqlMinDate = new DateTime(1753, 1, 1);
private static readonly DateTime SqlMaxDate = new DateTime(9998, 12, 31); // 9999 is not supported by the control
private static readonly DateTime SqlNullDate = new DateTime(1900, 1, 1);
public DataGridViewDataTimePickerEditingControl()
{
// activate the check box and set the range
base.ShowCheckBox = true;
base.MinDate = SqlMinDate;
base.MaxDate = SqlMaxDate;
}
#region common to all
public DataGridView EditingControlDataGridView { get; set; }
public int EditingControlRowIndex { get; set; }
public object EditingControlFormattedValue { get { return this.Value; } set { this.Value = value == null ? (DateTime?)null : Convert.ToDateTime(value); } }
public bool EditingControlValueChanged { get; set; }
public Cursor EditingPanelCursor { get { return Cursors.Default; } }
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) { return this.EditingControlFormattedValue; }
public bool RepositionEditingControlOnValueChange { get { return false; } }
#endregion
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
// set the calender font and colors
base.CalendarFont = dataGridViewCellStyle.Font;
base.CalendarForeColor = dataGridViewCellStyle.ForeColor;
base.CalendarMonthBackground = dataGridViewCellStyle.BackColor;
}
public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
{
switch (keyData & 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;
}
}
public void PrepareEditingControlForEdit(bool selectAll)
{
}
public override string Text
{
get
{
// return an empty string if the date/time is not set
return base.Checked ? base.Text : string.Empty;
}
set
{
base.Text = value;
}
}
public new DateTimePickerFormat Format
{
get { return base.Format; }
set
{
base.Format = value;
base.ShowUpDown = value == DateTimePickerFormat.Time;
}
}
[Bindable(true)]
[RefreshProperties(RefreshProperties.All)]
public new DateTime? Value
{
get
{ // get the appropriate return value
if (!base.Checked)
return null;
switch (base.Format)
{
case DateTimePickerFormat.Long:
case DateTimePickerFormat.Short:
return base.Value.Date;
case DateTimePickerFormat.Time:
return SqlNullDate + TimeSpan.FromTicks(base.Value.TimeOfDay.Ticks);
default:
return base.Value;
}
}
set
{
// set the (default) value and the check box
base.Value = value.HasValue ? value.Value : DateTime.Now;
base.Checked = value.HasValue;
}
}
protected override void OnValueChanged(EventArgs eventargs)
{
// forward the event and mark the cell as dirty
base.OnValueChanged(eventargs);
if (this.EditingControlDataGridView != null)
{
this.EditingControlValueChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
}
}
}
[ToolboxBitmap(typeof(ComboBox), "ComboBox.bmp")]
public class DataGridViewComboBoxExColumn : DataGridViewTypedColumn<DataGridViewComboBoxExEditingControl>
{
private static readonly CellProperty<object> DataSourceProperty = new CellProperty<object>(t => t.DataSource);
private static readonly CellProperty<string> DisplayMemberProperty = new CellProperty<string>(t => t.DisplayMember);
private static readonly CellProperty<string> ValueMemberProperty = new CellProperty<string>(t => t.ValueMember);
private static readonly CellProperty<string> ExpressionProperty = new CellProperty<string>(t => t.Expression);
/// <summary>
/// Gets or sets the data source that populates the selections for the combo boxes.
/// </summary>
[DefaultValue((string)null), AttributeProvider(typeof(IListSource)), RefreshProperties(RefreshProperties.Repaint)]
public object DataSource
{
get { return DataSourceProperty[this]; }
set { DataSourceProperty[this] = value; }
}
/// <summary>
/// Gets or sets a string that specifies the property or column from which to retrieve strings for display in the combo boxes.
/// </summary>
[DefaultValue(""), Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor)), TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public string DisplayMember
{
get { return DisplayMemberProperty[this]; }
set { DisplayMemberProperty[this] = value; }
}
/// <summary>
/// Gets or sets a string that specifies the property or column from which to get values that correspond to the selections in the drop-down list.
/// </summary>
[DefaultValue(""), Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor)), TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public string ValueMember
{
get { return ValueMemberProperty[this]; }
set { ValueMemberProperty[this] = value; }
}
/// <summary>
/// Gets or sets the expression used to filter rows, calculate the values in a column, or create an aggregate column.
/// </summary>
[DefaultValue("")]
public string Expression
{
get { return ExpressionProperty[this]; }
set { ExpressionProperty[this] = value; }
}
}
public class DataGridViewComboBoxExEditingControl : ComboBox, IDataGridViewEditingControl
{
private class DataExpression
{
private static readonly Type Type;
private static readonly ConstructorInfo Constructor;
private static readonly MethodInfo EvaluateMethod;
private static readonly MethodInfo BindMethod;
private static readonly PropertyInfo ExpressionProperty;
static DataExpression()
{
// reflect the underlying DataExpression type
Type = Assembly.GetAssembly(typeof(DataTable)).GetType("System.Data.DataExpression");
Constructor = Type.GetConstructor(BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(DataTable), typeof(string), typeof(Type) }, null);
BindMethod = Type.GetMethod("Bind", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(DataTable) }, null);
EvaluateMethod = Type.GetMethod("Evaluate", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(DataRow), typeof(DataRowVersion) }, null);
ExpressionProperty = Type.GetProperty("Expression", BindingFlags.Instance | BindingFlags.NonPublic, null, typeof(string), Type.EmptyTypes, null);
}
private object expression;
private DataTable boundTo;
public DataExpression(string expression)
{
if (expression == null)
throw new ArgumentNullException("expression");
try { this.expression = Constructor.Invoke(new object[] { null, expression, typeof(string) }); }
catch (TargetInvocationException e) { throw e.InnerException; }
}
public string Evaluate(DataRowView dataRowView)
{
// check the input, bind the expression if necessary and evaluate it
if (dataRowView == null)
throw new ArgumentNullException("dataRow");
if (this.boundTo != dataRowView.Row.Table)
{
BindMethod.Invoke(this.expression, new object[] { dataRowView.Row.Table });
this.boundTo = dataRowView.Row.Table;
}
return dataRowView.Row.HasVersion(dataRowView.RowVersion) ? (string)EvaluateMethod.Invoke(this.expression, new object[] { dataRowView.Row, dataRowView.RowVersion }) : null;
}
public string Value
{
get { return (string)ExpressionProperty.GetValue(this.expression, null); }
}
}
private DataExpression expression = null;
public DataGridViewComboBoxExEditingControl()
{
// set the proper defaults
base.AutoCompleteMode = AutoCompleteMode.Suggest;
base.AutoCompleteSource = AutoCompleteSource.ListItems;
base.DropDownStyle = ComboBoxStyle.DropDownList;
base.FormattingEnabled = false;
}
#region common to all
public DataGridView EditingControlDataGridView { get; set; }
public int EditingControlRowIndex { get; set; }
public object EditingControlFormattedValue { get { return this.SelectedIndex == -1 ? null : this.SelectedValue; } set { if (value == null) this.SelectedIndex = -1; else this.SelectedValue = value; } }
public bool EditingControlValueChanged { get; set; }
public Cursor EditingPanelCursor { get { return Cursors.Default; } }
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) { return this.EditingControlFormattedValue; }
public bool RepositionEditingControlOnValueChange { get { return false; } }
#endregion
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
// set the font, colors and format provider
this.Font = dataGridViewCellStyle.Font;
this.ForeColor = dataGridViewCellStyle.ForeColor;
this.BackColor = dataGridViewCellStyle.BackColor;
}
public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
{
switch (keyData & Keys.KeyCode)
{
case Keys.Up:
case Keys.Down:
case Keys.Delete:
// always handle UP, DOWN and DEL
return true;
case Keys.Enter:
case Keys.Escape:
// only handle ENTER and ESC if the list is shown
return base.DroppedDown;
default:
return !dataGridViewWantsInputKey;
}
}
public void PrepareEditingControlForEdit(bool selectAll)
{
// drop down the list for convenience
if (selectAll)
base.DroppedDown = true;
}
protected override void OnVisibleChanged(EventArgs e)
{
// hide the list if the box is hidden
if (!base.Visible && base.DroppedDown)
base.DroppedDown = false;
}
protected override void OnKeyUp(KeyEventArgs e)
{
// clear the selection if DEL is pressed
base.OnKeyUp(e);
if (e.KeyCode == Keys.Delete && e.Modifiers == 0)
{
// close the dropped down list if necessary
if (base.DroppedDown)
base.DroppedDown = false;
this.SelectedIndex = -1;
}
}
protected override bool AllowSelection
{
get { return false; }
}
protected override void OnFormat(ListControlConvertEventArgs e)
{
base.OnFormat(e);
e.Value = this.expression.Evaluate((DataRowView)e.ListItem);
}
protected override void OnDataSourceChanged(EventArgs e)
{
base.OnDataSourceChanged(e);
}
public string Expression
{
get { return this.expression == null ? string.Empty : this.expression.Value; }
set
{
var isEmpty = string.IsNullOrEmpty(value);
this.expression = isEmpty ? null : new DataExpression(value);
this.FormattingEnabled = !isEmpty;
}
}
protected override void OnSelectedValueChanged(EventArgs eventargs)
{
// forward the event and mark the cell as dirty
base.OnSelectedValueChanged(eventargs);
if (this.EditingControlDataGridView != null)
{
this.EditingControlValueChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
}
}
}
[ToolboxBitmap(typeof(NumericUpDown), "NumericUpDown.bmp")]
public class DataGridViewNumericUpDownColumn : DataGridViewTypedColumn<DataGridViewNumericUpDownEditingControl>
{
private static readonly CellProperty<int> PrecisionProperty = new CellProperty<int>(t => t.Precision);
private static readonly CellProperty<int> ScaleProperty = new CellProperty<int>(t => t.Scale);
private static readonly CellProperty<bool> ThousandsSeparatorProperty = new CellProperty<bool>(t => t.ThousandsSeparator);
/// <summary>
/// Gets or sets the maximum total number of decimal digits that will be stored, both to the left and to the right of the decimal point.
/// </summary>
/// <exception cref="System.ArgumentOutOfRangeException">The value is smaller than 1 or <see cref="Scale"/> or larger than 38.</exception>
[DefaultValue(18)]
public int Precision
{
get { return PrecisionProperty[this]; }
set { PrecisionProperty[this] = value; }
}
/// <summary>
/// Gets or sets the number of decimal digits that will be stored to the right of the decimal point.
/// </summary>
/// <exception cref="System.ArgumentOutOfRangeException">The value is smaller than 0 or larger than <see cref="Precision"/>.</exception>
[DefaultValue(0)]
public int Scale
{
get { return ScaleProperty[this]; }
set { ScaleProperty[this] = value; }
}
/// <summary>
/// Gets or sets a value indicating whether a thousands separator is displayed in the spin box (also known as an up-down control) when appropriate.
/// </summary>
[DefaultValue(false)]
public bool ThousandsSeparator
{
get { return ThousandsSeparatorProperty[this]; }
set { ThousandsSeparatorProperty[this] = value; }
}
}
public class DataGridViewNumericUpDownEditingControl : NumericUpDown, IDataGridViewEditingControl
{
private bool isNull = true;
private bool ignoreTextBoxKeyDown = false;
private bool ignoreKeyDown = false;
private int precision = 18;
#region common to all
public DataGridView EditingControlDataGridView { get; set; }
public int EditingControlRowIndex { get; set; }
public object EditingControlFormattedValue { get { return this.Value; } set { this.Value = value == null ? (decimal?)null : Convert.ToDecimal(value); } }
public bool EditingControlValueChanged { get; set; }
public Cursor EditingPanelCursor { get { return Cursors.Default; } }
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) { return this.EditingControlFormattedValue; }
public bool RepositionEditingControlOnValueChange { get { return false; } }
#endregion
public DataGridViewNumericUpDownEditingControl()
{
// set the initial limits
this.UpdateLimits();
}
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
// set the font, colors and format provider
this.Font = dataGridViewCellStyle.Font;
this.ForeColor = dataGridViewCellStyle.ForeColor;
this.BackColor = dataGridViewCellStyle.BackColor;
}
public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
{
switch (keyData & Keys.KeyCode)
{
case Keys.Left:
case Keys.Up:
case Keys.Down:
case Keys.Right:
return true;
default:
return !dataGridViewWantsInputKey;
}
}
public void PrepareEditingControlForEdit(bool selectAll)
{
// select all if necessary
if (selectAll)
base.Select(0, int.MaxValue);
}
protected override void UpdateEditText()
{
// end any pending editing and set the text
if (base.UserEdit)
this.EndUserEdit();
base.ChangingText = true;
this.Text = this.isNull ? string.Empty : base.Value.ToString((base.ThousandsSeparator ? "N" : "F") + base.DecimalPlaces);
}
private void EndUserEdit()
{
// parse the value the user has entered
try
{
if (!string.IsNullOrEmpty(this.Text))
{
var v = default(decimal);
if (decimal.TryParse(this.Text, out v))
{
// round, constrain and set the value
v = decimal.Round(v, base.DecimalPlaces);
if (v < base.Minimum)
v = base.Minimum;
if (v > base.Maximum)
v = base.Maximum;
this.Value = v;
}
}
else
this.Value = null;
}
finally
{
base.UserEdit = false;
}
}
protected override void ValidateEditText()
{
// change the behavior to include the possibility for null values
this.EndUserEdit();
this.UpdateEditText();
}
public override void DownButton()
{
// always end the user edit before forwarding the call
if (base.UserEdit)
this.EndUserEdit();
base.DownButton();
}
public override void UpButton()
{
// always end the user edit before forwarding the call
if (base.UserEdit)
this.EndUserEdit();
base.UpButton();
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
// avoid recursion from this method
if (this.ignoreKeyDown)
return;
base.OnKeyPress(e);
// only handle events originating from outside the textbox
if (!this.ignoreTextBoxKeyDown)
{
// check if the pressed key is valid
this.ignoreKeyDown = true;
try { base.OnTextBoxKeyPress(this, e); }
finally { this.ignoreKeyDown = false; }
// if so, set the textbox value
if (!e.Handled)
{
// prevent parsing if the value isn't yet parsable
var text = e.KeyChar.ToString();
var dummy = default(decimal);
this.ChangingText = !decimal.TryParse(text, out dummy);
this.Text = text;
this.Select(1, 0);
}
}
}
protected override void OnTextBoxKeyPress(object source, KeyPressEventArgs e)
{
// ignore any nested OnKeyPress
if (this.ignoreTextBoxKeyDown)
base.OnTextBoxKeyPress(source, e);
this.ignoreTextBoxKeyDown = true;
try { base.OnTextBoxKeyPress(source, e); }
finally { this.ignoreTextBoxKeyDown = false; }
}
private void UpdateLimits()
{
// set the limits according to precision and scale
var limit = this.Precision == this.Scale ? decimal.One : (new decimal(Math.Pow(10, this.Precision - this.Scale)) - decimal.One);
base.Minimum = -limit;
base.Maximum = limit;
}
public int Precision
{
get { return this.precision; }
set
{
if (value < 1 || value > 38 || value < this.Scale)
throw new ArgumentOutOfRangeException("Precision");
this.precision = value;
this.UpdateLimits();
}
}
public new int Scale
{
get { return base.DecimalPlaces; }
set
{
if (value < 0 || value > this.Precision)
throw new ArgumentOutOfRangeException("Scale");
base.DecimalPlaces = value;
this.UpdateLimits();
}
}
[Bindable(true)]
public new decimal? Value
{
get
{
// finish any editing
if (base.UserEdit)
this.ValidateEditText();
// either return null or the value
if (this.isNull)
return null;
return base.Value;
}
set
{
// cancel any editing
if (base.UserEdit)
base.UserEdit = false;
// set the value and the null flag
base.Value = value == null ? decimal.Zero : (decimal)value;
if (this.isNull != (value == null))
{
this.isNull = value == null;
this.OnValueChanged(EventArgs.Empty);
this.UpdateEditText();
}
}
}
protected override void OnValueChanged(EventArgs eventargs)
{
// forward the event and mark the cell as dirty
base.OnValueChanged(eventargs);
if (this.EditingControlDataGridView != null)
{
this.EditingControlValueChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment