.NET — управление Текстовым полем - ожидает, пока пользователь не сделан, введя

Из стр. 108 из Шаблоны проектирования: Элементы многоразового объектно-ориентированного программного обеспечения Гамма, Шлем, Джонсон и Влиссидес.

Используйте шаблон Factory Method, когда

  • класс не может предвидеть класс объектов, которые он должен создать
  • , класс хочет, чтобы его подклассы указывали объекты, которые он создает.
  • классы делегируют ответственность одному из нескольких вспомогательных подклассов, и вы хотите локализовать знание того, какой вспомогательный подкласс является делегатом

16
задан Cj Anderson 23 March 2009 в 00:06
поделиться

5 ответов

Один подход:

  1. Создают Timer с Interval из X миллисекунд

    , интервал должен составить приблизительно 300 мс; больше, чем нормальное время между нажатиями клавиш, и также разумный срок для ожидания между окончанием и обновлением, происходящим

  2. Во входе TextChanged событие Stop() и затем Start() Timer

    , Это перезапустит Timer, если это будет уже работать, поэтому если пользователь будет продолжать вводить при нормальном темпе, то каждое изменение перезапустит таймер.

  3. В таймере Tick событие, Stop() Timer и делают длинную транзакцию

  4. Дополнительный: Обработайте Leave и KeyDown события так, чтобы выходить из-под контроля или нажатие Вошли будет Stop() Timer и делают длинную транзакцию.

Это вызовет обновление, если текст изменился, и пользователь не внес изменений в X миллисекундах.

Одна проблема с "Мерой время начиная с последнего обновления" подход, который Вы рассматриваете, - то, что, если последнее изменение внесено быстро, обновления не произойдет, и не будет никаких последующих изменений для инициирования другой проверки.

Примечание: должен быть один к одному соединению между [1 114] es и Timer с; если бы Вы - планирование выполнения этого больше чем с одним входом, я рассмотрел бы создание UserControl, который обертывает эту функциональность.

34
ответ дан 30 November 2019 в 16:10
поделиться

Это зависит от того, что Вы подразумеваете "под сделанным вводом". Существует событие для сообщения, когда пользователь оставил фокус того конкретного управления. Кроме того, существует измененный даже, который говорит Вам, когда текст изменяется. То, что Вы могли сделать, захватить две вещи:

1) Потерянный фокус

2) Каждый раз пользователь изменяет текст, запустите, таймер для говорят, 20 секунд, и если пользователь сделан в течение того времени, то пользователь "сделан", введя. Это - то, если пользователь ничего не сделал в течение того времени, тогда предполагают, что пользователь "сделан".

, Если любая из тех двух вещей происходит тогда, пользователь сделан, удостоверьтесь, что остановили и перезапустили таймер соответственно. Очевидно, Вы могли изменить тайм-аут.

Все это зависит от того, как Вы хотите определить его.

1
ответ дан 30 November 2019 в 16:10
поделиться

Подход, который я использовал успешно в прошлом использовании ручное событие сброса и асинхронные вызовы для обнаружения, когда пользователь прекратил вводить. Код выглядит примерно так

// use manual reset event to Q up waiting threads.
// each new text changed event clears the Q
// only the last changed will hit the timeout, triggering the action
private ManualResetEvent _delayMSE;
private Func<bool> TBDelay = () => !_delayMSE.WaitOne(600, false);
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    SendOrPostCallback ActionToRunWhenUserStopsTyping = o =>
    {
        // ...
    };

    _delayMSE.Set(); // open the ResetEvent gate, to discard these delays
    Thread.Sleep(0); // let all pending through the gate
    _delaySearchMSE.Reset(); // close the gate
    TBDelay.BeginInvoke(res =>
    {
        // callback code
        // check how we exited, via timeout or signal.
        bool timedOut = TBDelay.EndInvoke(res);
        if (timedOut)
            Dispatcher.Invoke(DispatcherPriority.Input, 
                            ActionToRunWhenUserStopstyping,null);
    }, null);
}
0
ответ дан 30 November 2019 в 16:10
поделиться

В итоге я попробовал ответить Скотта Вайнштейна, хотя для этого потребовались некоторые более глубокие знания о потоках, делегатах и ​​базовом синтаксисе лямбда. И это сработало очень хорошо. Его первоначальный ответ не был чистым копипастом, поэтому мне пришлось немного поиграться, чтобы заставить его работать.

Я добавил очень мало времени в Thread.Sleep, так как заметил, что метод вызова может сработать дважды, если пользователь набирает текст очень быстро. но с крошечной случайной задержкой между некоторыми нажатиями клавиш. Вы также должны добавить ссылку на сборку WindowsBase для использования Dispatcher.

Я использую 1,5 секунды, чтобы дождаться завершения ввода пользователем.

    // use manual reset event to Q up waiting threads.
    // each new text changed event clears the Q
    // only the last changed will hit the timeout, triggering the action
    private ManualResetEvent _delayMSE;
    private Func<bool> TBDelay;
    private delegate void ActionToRunWhenUserStopstyping();

    public Form1()
    {
        InitializeComponent();

        _delayMSE = new ManualResetEvent(false);
        TBDelay = () => !_delayMSE.WaitOne(1500, false);
    }

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        _delayMSE.Set(); 

        // open the ResetEvent gate, to discard these delays    
        Thread.Sleep(20);
        // let all pending through the gate    
        _delayMSE.Reset();
        // close the gate
        TBDelay.BeginInvoke(res =>    
        {        
            // callback code        
            // check how we exited, via timeout or signal.        
            bool timedOut = TBDelay.EndInvoke(res);
            if (timedOut)
                Dispatcher.CurrentDispatcher.Invoke(
                    new ActionToRunWhenUserStopstyping(DoWhatEverYouNeed), 
                    DispatcherPriority.Input);
        }, null);
    }

    private void DoWhatEverYouNeed()
    {
        MessageBox.Show(textBox1.Text);
    }
3
ответ дан 30 November 2019 в 16:10
поделиться

Для тех, кому нужно что-то подобное в .NET 2.0, здесь я сделал элемент управления, который происходит от TextBox и использует тот же подход... Надеюсь, это поможет

public partial class TextBox : System.Windows.Forms.TextBox
{

    private ManualResetEvent _delayMSE;
    public event EventHandler OnUserStopTyping;
    private delegate bool TestTimeout();

    public TextBox()
    {
        _delayMSE = new ManualResetEvent(false);
        this.TextChanged += new EventHandler(TextBox_TextChanged);
    }

    void TextBox_TextChanged(object sender, EventArgs e)
    {


        _delayMSE.Set();
        Thread.Sleep(20);
        _delayMSE.Reset();

        TestTimeout tester = new TestTimeout(TBDelay);
        tester.BeginInvoke(new AsyncCallback(Test), tester);

    }


    private void Test(IAsyncResult pResult)
    { 
        bool timedOut = (bool)((TestTimeout)pResult.AsyncState).EndInvoke(pResult);
        if (timedOut)
        {
            if (OnUserStopTyping != null)
                OnUserStopTyping(this, null);
        }
    }

    private bool TBDelay()
    { 
        return !_delayMSE.WaitOne(500, false); 
    }

}
5
ответ дан 30 November 2019 в 16:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: