在textbox_textchanged上执行延迟

时间:2014-09-24 15:26:31

标签: c# winforms validation

我有一个模拟键盘输入的条形码扫描仪。我用它在一个文本框中输入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位数的方法。条形码扫描器模拟按下的各个键,这就是它当前失败的原因。

4 个答案:

答案 0 :(得分:13)

您可以在WPF中使用Timer(或DispatcherTimer)。此示例应用程序在最后一次击键后300ms更新窗口的标题。

    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语法可视化工具

答案 1 :(得分:1)

我建议使用Microsoft Reactive Extensions作为nuget包提供的解决方案。

Reactive Extensions是一个使用可观察集合和LINQ样式查询运算符组成异步和基于事件的程序的库。

如果使用RX扩展,只需两行代码即可解决问题:

注册活动:此处有count == 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));

答案 2 :(得分:0)

检查这是否有帮助。

    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");
        }
    }

答案 3 :(得分:0)

我寻求了计时器解决方案,并创建了一个简单的类来将其包装得更加整洁。 然后,如果需要,可以从表单中访问 TypingFinished 事件。

TextChanged 事件包装在 HandleCreated 事件中,以防止在将“应用程序设置”设置为文本框时调用该事件。

之所以调用

Settings.Default.Save 是因为它对我一直都是正确的,但也可以将其放入 TypingFinished 事件中。

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;
    }
}