对textbox_textchanged强制执行延迟
本文关键字:强制执行 延迟 textchanged textbox | 更新日期: 2023-09-27 18:24:10
我有一个模拟键盘输入的条形码扫描仪。我用它在一个文本框中输入ISBN编号,然后该文本框执行对该标题的搜索。在做任何事情之前,我需要文本框方法来等待一个10或13个字符的条目,但我不知道该怎么做。
到目前为止,我有以下内容:
private void scanBox_TextChanged(object sender, EventArgs e)
{
if (scanBox.Text.Length == 10)
{
getRecord10();
}
else if (scanBox.Text.Length == 13)
{
getRecord13();
}
else
{
MessageBox.Show("Not in directory", "Error");
}
}
我正在考虑某种定时器实现来推迟最后一个条件,但我真正需要的是该方法等待10或13位数字。条形码扫描仪模拟被按下的各个键,这就是它目前失败的原因。
您可以使用Timer(或WPF中的DispatcherTimer)。此示例应用程序在最后一次按键后300毫秒更新窗口的标题。
System.Windows.Forms.Timer _typingTimer; // WinForms
// System.Windows.Threading.DispatcherTimer _typingTimer; // WPF
public MainWindow()
{
InitializeComponent();
}
private void scanBox_TextChanged(object sender, EventArgs e)
{
if (_typingTimer == null)
{
/* WinForms: */
_typingTimer = new Timer();
_typingTimer.Interval = 300;
/* WPF:
_typingTimer = new DispatcherTimer();
_typingTimer.Interval = TimeSpan.FromMilliseconds(300);
*/
_typingTimer.Tick += new EventHandler(this.handleTypingTimerTimeout);
}
_typingTimer.Stop(); // Resets the timer
_typingTimer.Tag = (sender as TextBox).Text; // This should be done with EventArgs
_typingTimer.Start();
}
private void handleTypingTimerTimeout(object sender, EventArgs e)
{
var timer = sender as Timer; // WinForms
// var timer = sender as DispatcherTimer; // WPF
if (timer == null)
{
return;
}
// Testing - updates window title
var isbn = timer.Tag.ToString();
windowFrame.Text = isbn; // WinForms
// windowFrame.Title = isbn; // WPF
// The timer must be stopped! We want to act only once per keystroke.
timer.Stop();
}
部分代码取自Roslyn语法可视化工具
我提出了一个使用Microsoft Reactive Extensions的解决方案,该解决方案以nuget包的形式提供。
Reactive Extensions是一个库,用于使用可观察集合和LINQ风格的查询运算符来编写异步和基于事件的程序。
如果你使用RX扩展,你的问题只需两行代码就可以解决:
注册活动:这里有计数==10
IObservable<string> textChangedObservable =
Observable.FromEventPattern(textBox1, "TextChanged")
.Select(evt => ((TextBox)evt.Sender).Text).Where(x => x.Length == 10);
订阅活动:
textChangedObservable.Subscribe(e => MessageBox.Show(e));
检查这是否有帮助。
private System.Timers.Timer timer;
private void scanBox_TextChanged(object sender, EventArgs e)
{
if (scanBox.Text.Length == 10)
{
//wait for 10 chars and then set the timer
timer = new System.Timers.Timer(2000); //adjust time based on time required to enter the last 3 chars
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
}
}
private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
timer.Enabled = false;
if (scanBox.Text.Length == 10)
{
getRecord10();
}
else if (scanBox.Text.Length == 13)
{
getRecord13();
}
else
{
MessageBox.Show("Not in directory", "Error");
}
}
我选择了定时器解决方案,并创建了一个简单的类来更巧妙地封装它。如果需要,TypeingFinished事件将从窗体访问。
TextChanged事件包装在HandleCreated 调用Settings.Default.Save是因为它对我来说总是正确的,但也可以放在TypeingFinished事件中。 设计者代码:using YourApp.Properties;
using System;
using System.Windows.Forms;
namespace YourApp.Controls
{
public partial class TypeDelayTextBox : TextBox
{
public TypeDelayTextBox()
{
InitializeComponent();
this.HandleCreated += (senderX, argsX) => { this.TextChanged += OnTextChanged; };
}
private void OnTextChanged(object sender, EventArgs args)
{
_timer.Enabled = true;
_timer.Stop();
_timer.Start();
}
private void _timer_Tick(object sender, EventArgs e)
{
_timer.Stop();
Settings.Default.Save();
OnTypingFinished();
}
public event EventHandler TypingFinished;
protected virtual void OnTypingFinished()
{
TypingFinished?.Invoke(this, EventArgs.Empty);
}
}
}
namespace YourApp.Controls
{
partial class TypeDelayTextBox
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this._timer = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// _timer
//
this._timer.Interval = 3000;
this._timer.Tick += new System.EventHandler(this._timer_Tick);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Timer _timer;
}
}
这里有一个解决方案,用于在定时器周期后传递要调用的操作。感谢Amadeusz Wieczorek
asnwer:
private Timer _typingTimer;
private void textBox1_TextChanged(object sender, EventArgs e)
{
CheckTimer(() => { label1.Text = (sender as TextBox)?.Text; });
}
private void CheckTimer(Action act)
{
if (_typingTimer == null)
{
_typingTimer = new Timer { Interval = 350 };
_typingTimer.Tick += (sender, args) =>
{
if (!(sender is Timer timer))
return;
act?.Invoke();
timer.Stop();
};
}
_typingTimer.Stop();
_typingTimer.Start();
}