ComboBox 的事件 comboBox_TextChanged 并不总是触发
The event comboBox_TextChanged of the ComboBox does not always fire
我有一个输入应用程序,它从 ComboBox 中选择一个整数值。
Random 函数有一个种子,因此每次应用程序 运行 时都会生成相同的值序列。
通过在 ComboBox 中键入输入,如果前 2 位数字构成包含在 ComboBox.Items 列表中的值并添加第三位数字以便结果值不包含在 ComboBox.Items 列表中,则 _availableValuesForSelection_TextChanged 事件处理程序拒绝此数字。保留前 2 位数字。问题在于,如果多次添加相同的数字,最终结果值会被接受。我的结论是,几次后 ComboBox 的事件 _availableValuesForSelection_TextChanged 不会触发。
尝试添加 231,其中值 23 存在于 ComboBox.Items 列表中,还有 230 但不存在 231。
代码是:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace IntegerSelection
{
public partial class Form_SelectInteger : Form
{
public Form_SelectInteger(List<int> selectableValuesSource)
{
InitializeComponent();
_validValue = "";
_selectableValuesSource = selectableValuesSource;
_availableValuesForSelection = new ComboBox();
// The Source should be set first and then the AutoCompleteMode, otherwise it throws a NotSupportedException.
_availableValuesForSelection.BindingContext = new BindingContext(); // Create a new context.
_availableValuesForSelection.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
_availableValuesForSelection.AutoCompleteSource = AutoCompleteSource.ListItems;
_availableValuesForSelection.DropDownStyle = ComboBoxStyle.DropDown;
_availableValuesForSelection.DroppedDown = false;
_availableValuesForSelection.DrawMode = DrawMode.Normal;
_availableValuesForSelection.Enabled = true;
_availableValuesForSelection.BackColor = Color.LightBlue;
_availableValuesForSelection.ForeColor = Color.DarkBlue;
_availableValuesForSelection.IntegralHeight = false;
_availableValuesForSelection.MaxDropDownItems = 1;
_availableValuesForSelection.MaxDropDownItems = 80;
_availableValuesForSelection.DropDownHeight = 510;
_availableValuesForSelection.DropDownWidth = 50;
_availableValuesForSelection.TabStop = true;
_availableValuesForSelection.Visible = true;
_availableValuesForSelection.Width = 100;
_availableValuesForSelection.Location = new Point((this.Width - _availableValuesForSelection.Width) / 2, 150);
_availableValuesForSelection.DataSource = _selectableValuesSource; // DataSource should be the last line.
_availableValuesForSelection.SelectedIndex = 5;
this.Controls.Add(_availableValuesForSelection);
_button_SelectionCompleteWasPressed = false;
_availableValuesForSelection.TextChanged += new EventHandler(_availableValuesForSelection_TextChanged);
_selectedValue = (int)_availableValuesForSelection.Items[_availableValuesForSelection.SelectedIndex];
}
void _availableValuesForSelection_TextChanged(object sender, EventArgs e)
{
_textChangedEventDisabled = true;
string resultingText = _availableValuesForSelection.Text;
textBox1.Text = resultingText;
if (_availableValuesForSelection.FindString(resultingText) == -1)
{
while (_availableValuesForSelection.FindString(resultingText) == -1)
{
resultingText = resultingText.Substring(0, resultingText.Length - 1);
}
_availableValuesForSelection.DroppedDown = false;
_availableValuesForSelection.SelectedIndex = _availableValuesForSelection.FindString(resultingText);
_availableValuesForSelection.Text = resultingText;
_availableValuesForSelection.SelectionStart = _availableValuesForSelection.Text.Length;
_availableValuesForSelection.SelectionLength = 0;
}
_textChangedEventDisabled = false;
}
private ComboBox _availableValuesForSelection;
private List<int> _selectableValuesSource;
private int _selectedValue;
public int SelectedValue
{
get
{
return _selectedValue;
}
}
private string _validValue;
bool _textChangedEventDisabled = false;
private bool _button_SelectionCompleteWasPressed;
private void ValuesForSelection_SelectedIndexChanged(object sender, EventArgs e)
{
if (sender is ComboBox)
{
ComboBox displayValuesForSelection = (ComboBox)sender;
if (_button_SelectionCompleteWasPressed)
{
_selectedValue = (int)displayValuesForSelection.Items[displayValuesForSelection.SelectedIndex];
DialogResult = DialogResult.OK;
}
}
}
private void button_SelectionComplete_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK; // This line sets the DialogResult to OK to let the other form know that it wasn't forced closed or canceled.
_availableValuesForSelection.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
_availableValuesForSelection.AutoCompleteSource = AutoCompleteSource.ListItems;
_availableValuesForSelection.DropDownStyle = ComboBoxStyle.DropDown;
_button_SelectionCompleteWasPressed = true;
_selectedValue = (int)_availableValuesForSelection.Items[_availableValuesForSelection.SelectedIndex];
this.Close();
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace IntegerSelection
{
public partial class Form_Main : Form
{
Random rnd = new Random(0);
public Form_Main()
{
InitializeComponent();
PopulateValuesForSelection();
Form_SelectInteger integerSelection = new Form_SelectInteger(_selectableValues);
DialogResult result = integerSelection.ShowDialog(); // This line calls it as a Modal dialog, and retrieves its response once it's closed.
if (result == DialogResult.OK) // Test to see if the DialogResult was "OK".
{
_selectedValue = integerSelection.SelectedValue;
textBox1.ReadOnly = true;
textBox1.Text = _selectedValue.ToString();
}
else
{
this.Close();
Application.Exit();
}
}
private List<int> _selectableValues;
private int _selectedValue;
/// <summary>
/// The values included into _selectableValues must be unique (no duplicates are allowed).
/// </summary>
private void PopulateValuesForSelection()
{
_selectableValues = new List<int>();
HashSet<int> uniqueValues = new HashSet<int>();
int i = 0;
while (i < 256)
{
int currentValue = rnd.Next(0, 1000);
List<int> constituentDigits = SplitNumberIntoDigits(currentValue);
HashSet<int> digits = new HashSet<int>(constituentDigits);
if (!constituentDigits.Contains(-1) && uniqueValues.Add(currentValue))
{
i = uniqueValues.Count;
_selectableValues.Add(currentValue);
}
}
_selectableValues.Sort();
}
private List<int> SplitNumberIntoDigits(int number)
{
List<int> constituentDigits = new List<int>();
while (number > 0)
{
int digit = number % 10; // Get the last digit in the number.
constituentDigits.Insert(0, digit); // Insert the digit in the first location in the list, as it is the digit preceding the digit that is now in the first location in the list.
number = number / 10; // Shorten the integer by one digit, from the right (the least significant digit).
}
return constituentDigits;
}
}
}
请帮忙。
提前谢谢你。
Text属性 值更新时会引发 TextChanged 事件。对此进行了调查,似乎当您在输入无效字符后拒绝该值时,该值仍存储在对象内部的某个位置,并且不会在重复尝试时触发事件。
而每次文本在显示之前更改时都会触发 TextUpdate 事件。这用于验证文本输入,并且当文本 属性 以编程方式更改时不会触发。这听起来正是您想要的。
查看文档:
TextUpdate Event
您的代码只需更改一行即可运行:
_availableValuesForSelection.TextUpdate += new EventHandler(_availableValuesForSelection_TextChanged);
我有一个输入应用程序,它从 ComboBox 中选择一个整数值。 Random 函数有一个种子,因此每次应用程序 运行 时都会生成相同的值序列。 通过在 ComboBox 中键入输入,如果前 2 位数字构成包含在 ComboBox.Items 列表中的值并添加第三位数字以便结果值不包含在 ComboBox.Items 列表中,则 _availableValuesForSelection_TextChanged 事件处理程序拒绝此数字。保留前 2 位数字。问题在于,如果多次添加相同的数字,最终结果值会被接受。我的结论是,几次后 ComboBox 的事件 _availableValuesForSelection_TextChanged 不会触发。 尝试添加 231,其中值 23 存在于 ComboBox.Items 列表中,还有 230 但不存在 231。 代码是:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace IntegerSelection
{
public partial class Form_SelectInteger : Form
{
public Form_SelectInteger(List<int> selectableValuesSource)
{
InitializeComponent();
_validValue = "";
_selectableValuesSource = selectableValuesSource;
_availableValuesForSelection = new ComboBox();
// The Source should be set first and then the AutoCompleteMode, otherwise it throws a NotSupportedException.
_availableValuesForSelection.BindingContext = new BindingContext(); // Create a new context.
_availableValuesForSelection.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
_availableValuesForSelection.AutoCompleteSource = AutoCompleteSource.ListItems;
_availableValuesForSelection.DropDownStyle = ComboBoxStyle.DropDown;
_availableValuesForSelection.DroppedDown = false;
_availableValuesForSelection.DrawMode = DrawMode.Normal;
_availableValuesForSelection.Enabled = true;
_availableValuesForSelection.BackColor = Color.LightBlue;
_availableValuesForSelection.ForeColor = Color.DarkBlue;
_availableValuesForSelection.IntegralHeight = false;
_availableValuesForSelection.MaxDropDownItems = 1;
_availableValuesForSelection.MaxDropDownItems = 80;
_availableValuesForSelection.DropDownHeight = 510;
_availableValuesForSelection.DropDownWidth = 50;
_availableValuesForSelection.TabStop = true;
_availableValuesForSelection.Visible = true;
_availableValuesForSelection.Width = 100;
_availableValuesForSelection.Location = new Point((this.Width - _availableValuesForSelection.Width) / 2, 150);
_availableValuesForSelection.DataSource = _selectableValuesSource; // DataSource should be the last line.
_availableValuesForSelection.SelectedIndex = 5;
this.Controls.Add(_availableValuesForSelection);
_button_SelectionCompleteWasPressed = false;
_availableValuesForSelection.TextChanged += new EventHandler(_availableValuesForSelection_TextChanged);
_selectedValue = (int)_availableValuesForSelection.Items[_availableValuesForSelection.SelectedIndex];
}
void _availableValuesForSelection_TextChanged(object sender, EventArgs e)
{
_textChangedEventDisabled = true;
string resultingText = _availableValuesForSelection.Text;
textBox1.Text = resultingText;
if (_availableValuesForSelection.FindString(resultingText) == -1)
{
while (_availableValuesForSelection.FindString(resultingText) == -1)
{
resultingText = resultingText.Substring(0, resultingText.Length - 1);
}
_availableValuesForSelection.DroppedDown = false;
_availableValuesForSelection.SelectedIndex = _availableValuesForSelection.FindString(resultingText);
_availableValuesForSelection.Text = resultingText;
_availableValuesForSelection.SelectionStart = _availableValuesForSelection.Text.Length;
_availableValuesForSelection.SelectionLength = 0;
}
_textChangedEventDisabled = false;
}
private ComboBox _availableValuesForSelection;
private List<int> _selectableValuesSource;
private int _selectedValue;
public int SelectedValue
{
get
{
return _selectedValue;
}
}
private string _validValue;
bool _textChangedEventDisabled = false;
private bool _button_SelectionCompleteWasPressed;
private void ValuesForSelection_SelectedIndexChanged(object sender, EventArgs e)
{
if (sender is ComboBox)
{
ComboBox displayValuesForSelection = (ComboBox)sender;
if (_button_SelectionCompleteWasPressed)
{
_selectedValue = (int)displayValuesForSelection.Items[displayValuesForSelection.SelectedIndex];
DialogResult = DialogResult.OK;
}
}
}
private void button_SelectionComplete_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK; // This line sets the DialogResult to OK to let the other form know that it wasn't forced closed or canceled.
_availableValuesForSelection.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
_availableValuesForSelection.AutoCompleteSource = AutoCompleteSource.ListItems;
_availableValuesForSelection.DropDownStyle = ComboBoxStyle.DropDown;
_button_SelectionCompleteWasPressed = true;
_selectedValue = (int)_availableValuesForSelection.Items[_availableValuesForSelection.SelectedIndex];
this.Close();
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace IntegerSelection
{
public partial class Form_Main : Form
{
Random rnd = new Random(0);
public Form_Main()
{
InitializeComponent();
PopulateValuesForSelection();
Form_SelectInteger integerSelection = new Form_SelectInteger(_selectableValues);
DialogResult result = integerSelection.ShowDialog(); // This line calls it as a Modal dialog, and retrieves its response once it's closed.
if (result == DialogResult.OK) // Test to see if the DialogResult was "OK".
{
_selectedValue = integerSelection.SelectedValue;
textBox1.ReadOnly = true;
textBox1.Text = _selectedValue.ToString();
}
else
{
this.Close();
Application.Exit();
}
}
private List<int> _selectableValues;
private int _selectedValue;
/// <summary>
/// The values included into _selectableValues must be unique (no duplicates are allowed).
/// </summary>
private void PopulateValuesForSelection()
{
_selectableValues = new List<int>();
HashSet<int> uniqueValues = new HashSet<int>();
int i = 0;
while (i < 256)
{
int currentValue = rnd.Next(0, 1000);
List<int> constituentDigits = SplitNumberIntoDigits(currentValue);
HashSet<int> digits = new HashSet<int>(constituentDigits);
if (!constituentDigits.Contains(-1) && uniqueValues.Add(currentValue))
{
i = uniqueValues.Count;
_selectableValues.Add(currentValue);
}
}
_selectableValues.Sort();
}
private List<int> SplitNumberIntoDigits(int number)
{
List<int> constituentDigits = new List<int>();
while (number > 0)
{
int digit = number % 10; // Get the last digit in the number.
constituentDigits.Insert(0, digit); // Insert the digit in the first location in the list, as it is the digit preceding the digit that is now in the first location in the list.
number = number / 10; // Shorten the integer by one digit, from the right (the least significant digit).
}
return constituentDigits;
}
}
}
请帮忙。 提前谢谢你。
Text属性 值更新时会引发 TextChanged 事件。对此进行了调查,似乎当您在输入无效字符后拒绝该值时,该值仍存储在对象内部的某个位置,并且不会在重复尝试时触发事件。
而每次文本在显示之前更改时都会触发 TextUpdate 事件。这用于验证文本输入,并且当文本 属性 以编程方式更改时不会触发。这听起来正是您想要的。
查看文档: TextUpdate Event
您的代码只需更改一行即可运行:
_availableValuesForSelection.TextUpdate += new EventHandler(_availableValuesForSelection_TextChanged);