在C#中,有没有一种方法可以等待用户在文本框中完成输入后再获取他们键入的值而无需按Enter键?
稍微修改了这个问题:
好的,我有一个简单的乘2计算器。
这是我想要它做的事情:用户将一个值(例如1000)输入到文本框中,它会自动显示2000。
这是发生的事情:当用户输入1时,它就立即乘以2并输出2。
在C#中,有没有一种方法可以等待用户在文本框中完成输入后再获取他们键入的值而无需按Enter键?
稍微修改了这个问题:
好的,我有一个简单的乘2计算器。
这是我想要它做的事情:用户将一个值(例如1000)输入到文本框中,它会自动显示2000。
这是发生的事情:当用户输入1时,它就立即乘以2并输出2。
我现在将"完成输入"定义为"用户已经输入了一些内容,但在一段时间后未继续输入任何内容"。以此为定义,我编写了一个从TextBox派生的小类,通过DelayedTextChanged
事件来扩展它。我不能保证它完整且没有bug,但经过了简单的测试。请随意更改和/或使用它。我将其称为MyTextBox
,因为我现在想不出更好的名称了。您可以使用DelayedTextChangedTimeout
属性来更改等待超时时间。默认值为10000毫秒(= 10秒)。
public class MyTextBox : TextBox
{
private Timer m_delayedTextChangedTimer;
public event EventHandler DelayedTextChanged;
public MyTextBox() : base()
{
this.DelayedTextChangedTimeout = 10 * 1000; // 10 seconds
}
protected override void Dispose(bool disposing)
{
if (m_delayedTextChangedTimer != null)
{
m_delayedTextChangedTimer.Stop();
if (disposing)
m_delayedTextChangedTimer.Dispose();
}
base.Dispose(disposing);
}
public int DelayedTextChangedTimeout { get; set; }
protected virtual void OnDelayedTextChanged(EventArgs e)
{
if (this.DelayedTextChanged != null)
this.DelayedTextChanged(this, e);
}
protected override void OnTextChanged(EventArgs e)
{
this.InitializeDelayedTextChangedEvent();
base.OnTextChanged(e);
}
private void InitializeDelayedTextChangedEvent()
{
if (m_delayedTextChangedTimer != null)
m_delayedTextChangedTimer.Stop();
if (m_delayedTextChangedTimer == null || m_delayedTextChangedTimer.Interval != this.DelayedTextChangedTimeout)
{
m_delayedTextChangedTimer = new Timer();
m_delayedTextChangedTimer.Tick += new EventHandler(HandleDelayedTextChangedTimerTick);
m_delayedTextChangedTimer.Interval = this.DelayedTextChangedTimeout;
}
m_delayedTextChangedTimer.Start();
}
private void HandleDelayedTextChangedTimerTick(object sender, EventArgs e)
{
Timer timer = sender as Timer;
timer.Stop();
this.OnDelayedTextChanged(EventArgs.Empty);
}
}
另一个简单的解决方案是在表单中添加计时器,将Interval属性设置为250,然后使用计时器的Tick事件,如下:
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
Calculate(); // method to calculate value
}
private void txtNumber_TextChanged(object sender, EventArgs e)
{
timer1.Stop();
timer1.Start();
}
<TextBox Text="{Binding Name, Delay=500}" />
这意味着源仅在500毫秒后更新。就我所看到的,它在输入框结束输入后才进行更新。顺便说一下,这个属性在其他场景中也很有用,比如ListBox等。
UpdateSourceTrigger=PropertyChanged
。 - MgSam我也面对了同样的挑战,以下是我的简单解决方案。这种方法可以正常工作。
public partial class Form2 : Form
{
static int VALIDATION_DELAY = 1500;
System.Threading.Timer timer = null;
public Form2()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
TextBox origin = sender as TextBox;
if (!origin.ContainsFocus)
return;
DisposeTimer();
timer = new System.Threading.Timer(TimerElapsed, null, VALIDATION_DELAY, VALIDATION_DELAY);
}
private void TimerElapsed(Object obj)
{
CheckSyntaxAndReport();
DisposeTimer();
}
private void DisposeTimer()
{
if (timer != null)
{
timer.Dispose();
timer = null;
}
}
private void CheckSyntaxAndReport()
{
this.Invoke(new Action(() =>
{
string s = textBox1.Text.ToUpper(); //Do everything on the UI thread itself
label1.Text = s;
}
));
}
}
private const int millisecondsToWait = 500;
private static DateTime s_lastTimeOfTyping;
private void SearchField_OnTextChanged(object sender, TextChangedEventArgs e)
{
var latestTimeOfTyping = DateTime.Now;
var text = ((TextBox)sender).Text;
Task.Run(()=>DelayedCheck(latestTimeOfTyping, text));
s_lastTimeOfTyping = latestTimeOfTyping;
}
private async Task DelayedCheck(DateTime latestTimeOfTyping, string text)
{
await Task.Delay(millisecondsToWait);
if (latestTimeOfTyping.Equals(s_lastTimeOfTyping))
{
// Execute your function here after last text change
// Will need to bring back to the UI if doing UI changes
}
}
public static class UIExtensionMethods
{
public static async Task<bool> GetIdle(this TextBox txb)
{
string txt = txb.Text;
await Task.Delay(500);
return txt == txb.Text;
}
}
使用方法:
if (await myTextBox.GetIdle()){
// typing has stopped, do stuff
}
我不知道onChange()是否只存在于旧版本的c#中,但我找不到它!
以下内容可用于检测用户何时按下Enter键或离开文本框,但仅在更改了一些文本后才有效:
//--- this block deals with user editing the textBoxInputFile --- //
private Boolean textChanged = false;
private void textBoxInputFile_TextChanged(object sender, EventArgs e) {
textChanged = true;
}
private void textBoxInputFile_Leave(object sender, EventArgs e) {
if (textChanged) {
fileNameChanged();
}
textChanged = false;
}
private void textBoxInputFile_KeyDown(object sender, KeyEventArgs e) {
if (textChanged & e.KeyCode == Keys.Enter) {
fileNameChanged();
}
textChanged = false;
}
//--- end block --- //
您可以使用文本框的 onChange()
事件。如果文本框中的文本已更改,请检查输入的值是否为数字,并根据其他值计算总值。