Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. 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.

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. The barcode scanner emulates individual keys being pressed, which is why it is currently failing.

like image 632
Wolfish Avatar asked Sep 24 '14 15:09

Wolfish


2 Answers

You can use Timer (or DispatcherTimer in WPF). This sample app updates window's title 300ms after the last keystroke.

    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

like image 54
Amadeusz Wieczorek Avatar answered Nov 12 '22 12:11

Amadeusz Wieczorek


I propose a solution using Microsoft Reactive Extensions which are available as a nuget package.

Reactive Extensions is a library to compose asynchronous and event-based programs using observable collections and LINQ-style query operators.

If you use the RX extensions your problem can be solved with just two lines of code:

Sign up for an event: here with 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));
like image 25
Postlagerkarte Avatar answered Nov 12 '22 13:11

Postlagerkarte