简体   繁体   English

强制延迟 textbox_textchanged

[英]Enforcing a delay on textbox_textchanged

I have a barcode scanner that emulates keyboard entry.我有一个模拟键盘输入的条形码扫描器。 I'm using it to enter ISBN numbers into a textbox, which then performs a search for that title.我用它将 ISBN 编号输入文本框,然后搜索该标题。 I need the textbox method to wait for wither a 10 or 13 character entry before doing anything, however I'm not sure how to go about doing it.我需要文本框方法在执行任何操作之前等待 10 或 13 个字符的输入,但我不确定如何 go 进行操作。

So far, I have the following:到目前为止,我有以下内容:

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

I'm considering some sort of timer implementation to hold off on that last condition, but what I really need is for the method to wait for either 10 or 13 digits.我正在考虑某种计时器实现来推迟最后一个条件,但我真正需要的是等待 10 或 13 位数字的方法。 The barcode scanner emulates individual keys being pressed, which is why it is currently failing.条形码扫描仪模拟按下的各个键,这就是它目前失败的原因。

You can use Timer (or DispatcherTimer in WPF).您可以使用 Timer(或 WPF 中的 DispatcherTimer)。 This sample app updates window's title 300ms after the last keystroke.此示例应用程序在最后一次击键后 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();
    }

Parts of code are taken from the Roslyn syntax visualizer部分代码取自 Roslyn 语法可视化工具

I propose a solution usingMicrosoft Reactive Extensions which are available as a nuget package.我提出了一个使用Microsoft Reactive Extensions的解决方案,它可以作为 nuget 包提供。

Reactive Extensions is a library to compose asynchronous and event-based programs using observable collections and LINQ-style query operators. Reactive Extensions 是一个库,用于使用可观察集合和 LINQ 样式的查询运算符组合异步和基于事件的程序。

If you use the RX extensions your problem can be solved with just two lines of code:如果您使用 RX 扩展,您的问题只需两行代码即可解决:

Sign up for an event: here with count == 10报名参加一个活动:这里 count == 10

    IObservable<string> textChangedObservable =
    Observable.FromEventPattern(textBox1, "TextChanged")
    .Select(evt => ((TextBox)evt.Sender).Text).Where(x => x.Length == 10);

Subscribe to the Event:订阅活动:

    textChangedObservable.Subscribe(e => MessageBox.Show(e));

Check if this helps.检查这是否有帮助。

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

I went for the timer solution and created a simple class to wrap it up a bit more neatly.我选择了计时器解决方案并创建了一个简单的类来将其包装得更整洁。 The TypingFinished event is then accessed from the Form if it is needed.如果需要,然后可以从 Form 访问TypingFinished事件。

The TextChanged event is wrapped inside the HandleCreated event to prevent it from being invoked when Application Settings are being set to the textbox. TextChanged事件包装在HandleCreated事件中,以防止在将应用程序设置设置为文本框时调用它。

Settings.Default.Save is called because it is always true for me, but could just as well be put in the TypingFinished event.调用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);
        }
    }
}

Designer code:设计师代码:

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

Here is a solution to pass an action to be invoked after the timer period.这是传递在计时器时间段后调用的操作的解决方案。 Thanks to Amadeusz Wieczorek asnwer:感谢Amadeusz Wieczorek的回答:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM