我终于找到了适合我的自定义NumericUpDownCell。 (链接:custom NumericUpDownCell,由Loathing创建。)一切都很好。
但现在又出现了一个新问题:如果我使用向上箭头增加要购买的产品数量,我想立即增加另一列(价格单元格)的价值(不是在离开单元格之后) 。如何创建一个在更改金额单元格值时作出反应的侦听器?
我尝试在DataGridView上使用CellValueChanged事件。但这反应很奇怪:首先当我启动应用程序时(我猜测DataGridView已经创建并且它对此做出了反应。)其次,在我取消选择我增加值的单元格后,它首先做出了反应。
我希望它在我点击向上箭头时立即做出反应。我想也许有一种方法来修改Loathing的代码来为此添加一个监听器?但我自己也没有能力做到这一点。除非有一个内置的方法,我还没有找到它?
答案 0 :(得分:0)
一个简单的解决方案是使用DataGridView的EditingControlShowing
事件,并为ValueChanged
EditingControl
事件注册一个事件处理程序,如下面的代码所示:
NumericUpDownEditingControl lastCtl = null;
EventHandler handler = null;
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
var ctl = e.Control as NumericUpDownEditingControl;
if (ctl != null) //&& ctl != lastCtl
{
if (handler == null) handler = new EventHandler(myUpDownCtl_ValueChanged); //save a handler has better performance
//Event => ValueChanged: just fires for Up/Dn btn or when press enter, TextChanged: also fired during user typing
if (lastCtl != null) lastCtl.ValueChanged -= handler; //ensure we remove our handler.
lastCtl = ctl;
lastCtl.ValueChanged += handler; //we can use myUpDownCtl_ValueChanged directly instead of that handler var
//handler(sender, EventArgs.Empty);
}
}
void myUpDownCtl_ValueChanged(object sender, EventArgs e)
{
MessageBox.Show("New value: " + lastCtl.Value.ToString());
//Grid1.CurrentRow.Cells[5].Value = lastCtl.Value * 10; //sample to change other columns based on this value
}
注意:ValueChanged
事件仅针对向上/向下按钮触发,或者当用户键入某个数字并按Enter键时触发。如果您想在Numeric TextBox内的用户类型时更新,请改用TextChanged
!
另请注意我在回答InitializeEditingControl
方法的答案时发表的评论。
更新
这是要测试的整个代码:
public partial class Form4 : Form
{
public Form4()
{
InitializeComponent();
}
private void Form4_Load(object sender, EventArgs e)
{
}
NumericUpDownEditingControl lastCtl = null;
EventHandler handler = null;
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
var ctl = e.Control as NumericUpDownEditingControl;
if (ctl != null) //&& ctl != lastCtl
{
if (handler == null) handler = new EventHandler(myUpDownCtl_ValueChanged); //save a handler has better performance
//Event => ValueChanged: just fires for Up/Dn btn or when press enter, TextChanged: also fired during user typing
if (lastCtl != null) lastCtl.ValueChanged -= handler; //ensure we remove our handler.
lastCtl = ctl;
lastCtl.ValueChanged += handler; //we can use myUpDownCtl_ValueChanged directly instead of that handler var
//handler(sender, EventArgs.Empty);
}
}
void myUpDownCtl_ValueChanged(object sender, EventArgs e)
{
//MessageBox.Show("New value: " + lastCtl.Value.ToString());
dataGridView1.CurrentRow.Cells[1].Value = lastCtl.Value * 10; //sample to change other columns based on this value
}
} //end Form
//****************************************************************
public class NumericUpDownColumn : DataGridViewColumn {
public NumericUpDownColumn() : base(new NumericUpDownCell()) {
this.ValueType = typeof(decimal?);
}
public override DataGridViewCell CellTemplate {
get {
return base.CellTemplate;
}
set {
if (!(value is NumericUpDownCell))
throw new InvalidCastException("Must be a NumericUpDownCell");
base.CellTemplate = value;
}
}
}
public class NumericUpDownCell : DataGridViewTextBoxCell {
public override void InitializeEditingControl(int rowIndex, Object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) {
// required to initialize the editing control:
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
var ctl = (NumericUpDownEditingControl) DataGridView.EditingControl;
//NumericUpDownColumn cc = (NumericUpDownColumn) this.OwningColumn;
if (this.Value == null || this.Value == DBNull.Value) {
ctl.Value = (ctl.Minimum <= 0 && ctl.Maximum >= 0 ? 0 : ctl.Minimum);
}
else {
Object trueValue = this.Value;
ctl.Value = Convert.ToDecimal(trueValue); //(decimal)trueValue;
}
}
public override Type EditType {
get {
return typeof(NumericUpDownEditingControl);
}
}
public override Type ValueType {
get {
return base.ValueType;
}
set {
base.ValueType = value;
}
}
public override Object DefaultNewRowValue {
get {
return DBNull.Value;
}
}
}
[ToolboxItem(false)] //don't show this as a new control in toolbox
public class NumericUpDownEditingControl : NumericUpDown, IDataGridViewEditingControl {
private bool Cancelling = false;
public NumericUpDownEditingControl() {
}
// Implements the IDataGridViewEditingControl.EditingControlFormattedValue property.
public Object EditingControlFormattedValue {
get {
// must return a String
// it doesn't matter if the value is formatted, it will be replaced
// by the formatting events
String s = "" + this.Value.ToString();
return s;
}
set {
decimal val = 0;
if (value is decimal)
this.Value = (decimal) value;
else {
String s = "" + value;
if (s.Length > 0) {
if (decimal.TryParse(s, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.CurrentCulture, out val))
this.Value = val;
}
}
}
}
protected override void OnLeave(EventArgs e) {
if (!Cancelling) {
var dgv = this.EditingControlDataGridView;
var cell = (NumericUpDownCell) dgv.CurrentCell;
cell.Value = this.Value;
}
base.OnLeave(e);
Cancelling = false;
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.KeyCode == Keys.Escape) {
Cancelling = true;
e.Handled = true;
e.SuppressKeyPress = true;
var dgv = this.EditingControlDataGridView;
dgv.CancelEdit();
dgv.EndEdit();
}
base.OnKeyDown(e);
}
// Implements the IDataGridViewEditingControl.GetEditingControlFormattedValue method.
public Object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) {
return EditingControlFormattedValue;
}
// Implements the IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) {
this.Font = dataGridViewCellStyle.Font;
this.ForeColor = dataGridViewCellStyle.ForeColor;
this.BackColor = dataGridViewCellStyle.BackColor;
}
// Implements the IDataGridViewEditingControl.EditingControlRowIndex property.
public int EditingControlRowIndex { get; set; }
// Implements the IDataGridViewEditingControl.EditingControlWantsInputKey method.
public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey) {
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:
case Keys.Escape:
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; set; }
// Implements the IDataGridViewEditingControl.EditingControlValueChanged property.
public bool EditingControlValueChanged { get; set; }
// Implements the IDataGridViewEditingControl.EditingPanelCursor property.
public Cursor EditingPanelCursor {
get {
return base.Cursor;
}
}
}