簡體   English   中英

強制延遲 textbox_textchanged

[英]Enforcing a delay on textbox_textchanged

我有一個模擬鍵盤輸入的條形碼掃描器。 我用它將 ISBN 編號輸入文本框,然后搜索該標題。 我需要文本框方法在執行任何操作之前等待 10 或 13 個字符的輸入,但我不確定如何 go 進行操作。

到目前為止,我有以下內容:

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 擴展,您的問題只需兩行代碼即可解決:

報名參加一個活動:這里 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));

檢查這是否有幫助。

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

我選擇了計時器解決方案並創建了一個簡單的類來將其包裝得更整潔。 如果需要,然后可以從 Form 訪問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;
    }
}

這是傳遞在計時器時間段后調用的操作的解決方案。 感謝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