C # aspetta che l’utente finisca di digitare in una casella di testo

C’è un modo in C # di aspettare fino a quando l’utente ha finito di digitare in una casella di testo prima di prendere i valori che hanno digitato senza premere invio?

Riveduto questa domanda un po ‘:

Va bene ho una calcolatrice semplice che moltiplica per 2.

Ecco cosa voglio che faccia: l’utente immette un valore come 1000 in una casella di testo e visualizza automaticamente 2000.

Ecco cosa succede: non appena l’utente entra in 1 si moltiplica per 2 e esce 2.

È ansible utilizzare l’evento onChange() . Se il testo viene modificato nella casella di testo, verificare se il valore immesso è un numero e calcolare il valore totale in base all’altro valore.

Definisco “terminato digitando” ora come “l’utente ha digitato qualcosa ma non ha digitato nulla dopo un certo tempo”. Avendo che come definizione ho scritto una piccola class che deriva da TextBox per estenderla con un evento DelayedTextChanged . Non sono sicuro che sia completo e privo di bug, ma ha soddisfatto un piccolo test del fumo. Sentiti libero di cambiare e / o usarlo. L’ho chiamato MyTextBox perché non riuscivo a trovare un nome migliore al momento. È ansible utilizzare la proprietà DelayedTextChangedTimeout per modificare il timeout di attesa. L’impostazione predefinita è 10000 ms (= 10 secondi).

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

Un’altra soluzione semplice sarebbe quella di aggiungere un timer al modulo, impostare la proprietà Interval su 250 e quindi utilizzare l’evento tick del timer come segue:

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

Se si utilizza WPF e .NET 4.5 o versioni successive, esiste una nuova proprietà nella parte Binding di un controllo denominato “Delay”. Definisce un intervallo dopo il quale la fonte viene aggiornata.

  

Ciò significa che l’origine viene aggiornata solo dopo 500 millisecondi. Per quanto vedo lo fa l’aggiornamento dopo aver digitato nel TextBox terminato. Btw. questa proprietà può essere utile anche in altri scenari, ad es. ListBox ecc.

È ansible gestire l’evento LostFocus della casella di testo che si triggers ogni volta che l’utente termina la digitazione e si allontana dalla casella di testo. Ecco la documentazione su LostFocus: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.lostfocus.aspx

Tuttavia, non sono sicuro di cosa stia esattamente cercando di fare in quanto la domanda non è molto chiara su cosa significa “finire”.

Ho affrontato la stessa sfida, ed ecco il mio approccio semplice. Questo funziona senza problemi.

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

In UWP, ho eseguito un controllo ritardato effettuando un static lastTimeOfTyping e controllando l’ora in cui si è verificato l’evento “TextChanged”. Questo attende che l’ultimo staticTimeOfTyping sia uguale quando una nuova ora “TextChanged” corrisponde e quindi esegue la funzione desiderata.

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

Si desidera utilizzare gestire l’evento Leave o LostFocus per la casella di testo in questione. Suppongo che tu stia usando WinForm anche se non lo dici nella tua domanda.

Non so se onChange () esiste solo in una versione precedente di c #, ma non riesco a trovarlo!

Il seguente funziona per rilevare quando un utente preme il tasto Invio o le tabs fuori dal TextBox, ma solo dopo aver modificato del testo:

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

Cosa succede se si triggers un evento in base a una sequenza di tasti come scheda o ritorno?

Un mio collega ha suggerito una soluzione utilizzando Rx e la limitazione degli eventi:

 var FindDelay = 500;//milliseconds //textBox is your text box element Observable.FromEventPattern(textBox, "TextChanged") .Select(ea => ((TextBox) ea.Sender).Text) .DistinctUntilChanged() .Throttle(TimeSpan.FromMilliseconds(FindDelay)) .Subscribe(text => { //your handler here });