C # ждать, пока пользователь закончит вводить текстовое поле - PullRequest
25 голосов
/ 04 ноября 2011

Есть ли способ в C # подождать, пока пользователь закончит вводить текстовое поле, прежде чем вводить введенные значения, не нажимая enter?

Немного изменил этот вопрос:

Хорошо, яу меня есть простой калькулятор, который умножается на 2.

Вот что я хочу сделать: пользователь вводит значение, например 1000, в текстовое поле, и оно автоматически отображает 2000.

Вот что происходит: Как только пользователь входит в 1, он умножается на 2 и выдает 2.

Ответы [ 13 ]

45 голосов
/ 04 ноября 2011

Теперь я определяю «законченный набор текста» как «пользователь что-то набрал, но ничего не набрал по истечении определенного времени».Имея это в качестве определения, я написал небольшой класс, производный от TextBox, чтобы расширить его на событие DelayedTextChanged.Я не гарантирую, что это завершено и без ошибок, но это удовлетворило небольшой тест дыма.Не стесняйтесь изменять и / или использовать его.Я назвал это MyTextBox, потому что я не мог придумать лучшее имя прямо сейчас.Вы можете использовать свойство DelayedTextChangedTimeout, чтобы изменить время ожидания.По умолчанию 10000 мс (= 10 секунд).

public class MyTextBox : TextBox
{
    private Timer m_delayedTextChangedTimer;

    public event EventHandler DelayedTextChanged;

    public MyTextBox() : base() 
    {
        this.DelayedTextChangedTimeout = 10 * 1000; // 10 seconds
    }

    protected override void Dispose(bool disposing)
    {
        if (m_delayedTextChangedTimer != null)
        {
            m_delayedTextChangedTimer.Stop();
            if (disposing)
                m_delayedTextChangedTimer.Dispose();
        }

        base.Dispose(disposing);            
    }

    public int DelayedTextChangedTimeout { get; set; }

    protected virtual void OnDelayedTextChanged(EventArgs e)
    {
        if (this.DelayedTextChanged != null)
            this.DelayedTextChanged(this, e);
    }

    protected override void OnTextChanged(EventArgs e)
    {
        this.InitializeDelayedTextChangedEvent();
        base.OnTextChanged(e);            
    }                

    private void InitializeDelayedTextChangedEvent()
    {
        if (m_delayedTextChangedTimer != null)
            m_delayedTextChangedTimer.Stop();

        if (m_delayedTextChangedTimer == null || m_delayedTextChangedTimer.Interval != this.DelayedTextChangedTimeout)
        {                
            m_delayedTextChangedTimer = new Timer();
            m_delayedTextChangedTimer.Tick += new EventHandler(HandleDelayedTextChangedTimerTick);
            m_delayedTextChangedTimer.Interval = this.DelayedTextChangedTimeout;
        }

        m_delayedTextChangedTimer.Start();
    }

    private void HandleDelayedTextChangedTimerTick(object sender, EventArgs e)
    {
        Timer timer = sender as Timer;
        timer.Stop();

        this.OnDelayedTextChanged(EventArgs.Empty);
    }
}
12 голосов
/ 06 февраля 2016

Если вы используете WPF и .NET 4.5 или более позднюю версию, в части Binding элемента управления с именем «Delay» появляется новое свойство. Он определяет временной интервал, после которого источник обновляется.

<TextBox Text="{Binding Name, Delay=500}" />

Это означает, что источник обновляется только через 500 миллисекунд. Насколько я вижу, обновление происходит после завершения ввода в TextBox. Btw. это свойство может быть полезно и в других сценариях, например. ListBox и т. Д.

11 голосов
/ 05 февраля 2015

Другое простое решение - добавить в форму таймер, установить для свойства Interval значение 250, а затем использовать событие тика таймера следующим образом:

private void timer1_Tick(object sender, EventArgs e)
{
    timer1.Stop();
    Calculate(); // method to calculate value
}

private void txtNumber_TextChanged(object sender, EventArgs e)
{
    timer1.Stop();
    timer1.Start();
}
5 голосов
/ 04 ноября 2011

Вы можете обработать событие LostFocus текстового поля, которое будет срабатывать каждый раз, когда пользователь заканчивает ввод текста и уходит от текстового поля.Вот документация по LostFocus: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.lostfocus.aspx

Однако я не уверен, что именно вы пытаетесь сделать здесь, так как вопрос не очень ясен о том, что означает «конец».

4 голосов
/ 09 февраля 2016

Я столкнулся с той же проблемой, и вот мой простой подход.Это работает без проблем.

public partial class Form2 : Form
    {
        static int VALIDATION_DELAY = 1500;
        System.Threading.Timer timer = null;
        public Form2()
        {
            InitializeComponent();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            TextBox origin = sender as TextBox;
            if (!origin.ContainsFocus)
                return;

            DisposeTimer();
            timer = new System.Threading.Timer(TimerElapsed, null, VALIDATION_DELAY, VALIDATION_DELAY);

        }
        private void TimerElapsed(Object obj)
        {
            CheckSyntaxAndReport();
            DisposeTimer();            
        }

        private void DisposeTimer()
        {
            if (timer != null)
            {
                timer.Dispose();
                timer = null;
            }
        }

        private void CheckSyntaxAndReport()
        {            
            this.Invoke(new Action(() => 
            {
                string s = textBox1.Text.ToUpper(); //Do everything on the UI thread itself
                label1.Text = s; 
            }
                ));            
        }
    }
3 голосов
/ 04 ноября 2011

Вы можете использовать текстовое поле onChange() событие. Если текст изменяется в текстовом поле, проверьте, является ли введенное значение числом, и вычислите общее значение в соответствии с другим значением.

2 голосов
/ 21 февраля 2018

В UWP я сделал отложенную проверку, сделав статический lastTimeOfTyping и проверив время, когда произошло событие TextChanged. Это ждет, пока статическое lastTimeOfTyping не совпадет, когда совпадет новое время «TextChanged», а затем выполнит требуемую функцию.

    private const int millisecondsToWait = 500;
    private static DateTime s_lastTimeOfTyping;
    private void SearchField_OnTextChanged(object sender, TextChangedEventArgs e)
    {
        var latestTimeOfTyping = DateTime.Now;
        var text = ((TextBox)sender).Text;
        Task.Run(()=>DelayedCheck(latestTimeOfTyping, text));
        s_lastTimeOfTyping = latestTimeOfTyping;
    }

    private async Task DelayedCheck(DateTime latestTimeOfTyping, string text)
    {
        await Task.Delay(millisecondsToWait);
        if (latestTimeOfTyping.Equals(s_lastTimeOfTyping))
        {
            // Execute your function here after last text change
            // Will need to bring back to the UI if doing UI changes
        }
    }
1 голос
/ 11 февраля 2019

В идеале решение для наследования, такое как esskar, является подходящим решением, но оно не очень подходит для дизайнера, поэтому для повторного использования я выбрал вспомогательный класс вспомогательного стиля:

using System;
using System.Threading;
using System.Windows.Forms;
using Timer = System.Threading.Timer;

    internal class DelayedText : IDisposable
    {
        private readonly EventHandler _onTextChangedDelayed;
        private readonly TextBox _textBox;
        private readonly int _period;
        private Timer _timer;

        public DelayedText(TextBox textBox, EventHandler onTextChangedDelayed, int period = 250)
        {
            _textBox = textBox;
            _onTextChangedDelayed = onTextChangedDelayed;
            _textBox.TextChanged += TextBoxOnTextChanged;
            _period = period;
        }

        public void Dispose()
        {
            _timer?.Dispose();
            _timer = null;
        }

        private void TextBoxOnTextChanged(object sender, EventArgs e)
        {
            Dispose();
            _timer = new Timer(TimerElapsed, null, _period, Timeout.Infinite);
        }

        private void TimerElapsed(object state)
        {
            _onTextChangedDelayed(_textBox, EventArgs.Empty);
        }
    }

Использование в конструкторе формы:

InitializeComponent();
...
new DelayedText(txtEdit, txtEdit_OnTextChangedDelayed);

Я не сильно ударил, но, похоже, мне подходит.

1 голос
/ 05 октября 2018

как метод асинхронного расширения.Адаптировано из ответа Grecon14.

public static class UIExtensionMethods
{
    public static async Task<bool> GetIdle(this TextBox txb)
    {
        string txt = txb.Text;
        await Task.Delay(500);
        return txt == txb.Text;
    }
}

Использование:

if (await myTextBox.GetIdle()){
    // typing has stopped, do stuff
}
1 голос
/ 06 марта 2014

Я не знаю, существует ли onChange () только в более старой версии c #, но я не могу его найти!

Следующее работает для определения, когда пользователь нажимает клавишу Enter или вкладки из TextBox, но только после изменения некоторого текста:

    //--- this block deals with user editing the textBoxInputFile --- //
    private Boolean textChanged = false;
    private void textBoxInputFile_TextChanged(object sender, EventArgs e) {
        textChanged = true;
    }
    private void textBoxInputFile_Leave(object sender, EventArgs e) {
        if (textChanged) {
            fileNameChanged();
        }
        textChanged = false;
    }
    private void textBoxInputFile_KeyDown(object sender, KeyEventArgs e) {
        if (textChanged & e.KeyCode == Keys.Enter) {
            fileNameChanged();
        }
        textChanged = false;
    }
    //--- end block  --- //
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...