texto - validaciones en c# un textbox
C#espera a que el usuario termine de escribir en un cuadro de texto (12)
¿Qué sucede si desencadena un evento en función de una pulsación de tecla o una pestaña?
¿Hay alguna forma en C # de esperar hasta que el usuario termine de escribir en un cuadro de texto antes de tomar los valores que ha escrito sin presionar entrar?
Revisé un poco esta pregunta:
De acuerdo tengo una calculadora simple que se multiplica por 2.
Esto es lo que quiero que haga: el usuario ingresa un valor como 1000 en un cuadro de texto y muestra automáticamente 2000.
Esto es lo que sucede: Tan pronto como el usuario ingresa en 1, se multiplica por 2 y sale 2.
Como método de extensión asíncrona. Adaptado de la respuesta de 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;
}
}
Uso:
if (await myTextBox.GetIdle()){
// typing has stopped, do stuff
}
Defino "terminé de escribir" ahora que "el usuario ha escrito algo pero no ha escrito nada después de un tiempo determinado". Teniendo eso como una definición, escribí una pequeña clase que se deriva de TextBox para extenderla mediante un evento DelayedTextChanged
. No me aseguro de que esté completo y libre de errores, pero cumplió con una pequeña prueba de humo. Siéntase libre de cambiarlo y / o usarlo. Lo llamé MyTextBox
porque no pude encontrar un nombre mejor en este momento. Puede usar la propiedad DelayedTextChangedTimeout
para cambiar el tiempo de espera de espera. El valor predeterminado es 10000ms (= 10 segundos).
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);
}
}
Desea utilizar el controlador Leave o http://msdn.microsoft.com/en-us/library/system.windows.forms.control.lostfocus.aspx para el cuadro de texto en cuestión. Supongo que está utilizando WinForm aunque no lo indique en su pregunta.
En UWP, realicé una comprobación retrasada al hacer un último TimeTimeOfTyping estático y comprobar el momento en que ocurrió el evento "TextChanged". Esto espera hasta que coincida el último TimeTimeOfTyping estático cuando coincide un nuevo tiempo de "TextChanged" y luego ejecuta la función deseada.
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
}
}
Me enfrenté al mismo desafío, y aquí está mi enfoque simple. Esto funciona sin problemas.
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;
}
));
}
}
No sé si onChange () solo existe en una versión anterior de c #, ¡pero no puedo encontrarlo!
Lo siguiente sirve para detectar cuándo un usuario pulsa la tecla Intro o salta del Cuadro de texto, pero solo después de cambiar un texto:
//--- 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 --- //
Otra solución simple sería agregar un temporizador a su formulario, establecer la propiedad Intervalo en 250 y luego usar el evento de tictac del temporizador de la siguiente manera:
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();
}
Puede controlar el evento LostFocus del cuadro de texto que se activará cada vez que el usuario termine de escribir y navegue fuera del cuadro de texto. Aquí está la documentación en LostFocus: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.lostfocus.aspx
Sin embargo, no estoy seguro de qué es exactamente lo que intentas hacer aquí, ya que la pregunta no es muy clara sobre qué significa "terminar".
Si está utilizando WPF y .NET 4.5 o posterior, hay una nueva propiedad en la parte de enlace de un control llamado "Retraso". Define un intervalo de tiempo después del cual se actualiza la fuente.
<TextBox Text="{Binding Name, Delay=500}" />
Esto significa que la fuente se actualiza solo después de 500 milisegundos. Por lo que veo, la actualización después de escribir el TextBox terminó. Por cierto Esta propiedad también puede ser útil en otros escenarios, por ejemplo. ListBox etc.
Un colega mío sugirió una solución utilizando Rx y la limitación de eventos:
var FindDelay = 500;//milliseconds
//textBox is your text box element
Observable.FromEventPattern<EventArgs>(textBox, "TextChanged")
.Select(ea => ((TextBox) ea.Sender).Text)
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliseconds(FindDelay))
.Subscribe(text => {
//your handler here
});
Puede usar el cuadro de texto en el evento onChange()
. Si el texto se cambia en el cuadro de texto, verifique si el valor ingresado es un número y calcule el valor total de acuerdo con el otro valor.