有没有在C#的方式要等到用户取完价值观,他们已经输入没有按下回车键之前,在文本框中键入?
修订这个问题有点:
好吧,我有一个简单的计算器,乘以2。
以下是我想做的事情:用户输入,比如1000的值到一个文本框,并自动显示2000。
下面是发生的情况:只要用户在1其乘以2个,并输出2进入。
您可以使用文本框onChange()
事件。如果文本在文本框改变,检查输入的值是一个数字,根据其他价值计算总值。
我不知道,如果的onChange()仅在旧版本的C#的存在,但我不能找到它!
用于检测以下工作当用户点击或者回车键,或者切换到该文本框的,但改变一些文字后才:
//--- 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 --- //
理想的情况是像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);
我还没有踢它很难,但似乎为我工作。
如果你触发基于像标签或返回键击的事件?
我的一位同事建议使用Rx和事件节流的解决方案:
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
});
如果用户在打字快,你要延迟计算,直到他停止了,然后下面的代码可以帮助键入:
private void valueInput_TextChanged(object sender, EventArgs e)
{
CalculateAfterStopTyping();
}
Thread delayedCalculationThread;
int delay = 0;
private void CalculateAfterStopTyping()
{
delay += 200;
if (delayedCalculationThread != null && delayedCalculationThread.IsAlive)
return;
delayedCalculationThread = new Thread(() =>
{
while (delay >= 200)
{
delay = delay - 200;
try
{
Thread.Sleep(200);
}
catch (Exception) {}
}
Invoke(new Action(() =>
{
// do your calcualation here...
}));
});
delayedCalculationThread.Start();
}
我定义“完成键入”现在是“用户键入的东西,但一定时间后还没有录入任何”。有了这样一个定义,我写了一个小的类,从文字框派生由DelayedTextChanged
事件来扩展它。我不保证完整和错误免费的,但它满足了小烟熏的考验。随意更改和/或使用它。我把它叫做MyTextBox
因为我无法想出一个更好的名字现在。您可以使用DelayedTextChangedTimeout
属性来更改等待超时。缺省值是10000ms(= 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);
}
}
如果您正在使用WPF和.NET 4.5或更高版本上有一个名为“延迟”控制的结合部的新属性。它定义在此之后,源被更新一个时间跨度。
<TextBox Text="{Binding Name, Delay=500}" />
这意味着源仅在500毫秒之后更新。据我看到它在结束文本框中键入后更新。顺便说一句。这个属性可以在其他情况下是有益的为好,例如。列表框等。
另一种简单的解决方案将是一个计时器添加到您的形式,Interval属性设置为250,然后使用计时器的Tick事件如下:
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();
}
您可以处理文本框时会触发每次用户完成输入和导航从文本框离开的LostFocus事件。这里是引发LostFocus文档:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.lostfocus.aspx
但是,我不知道究竟你正在试图为这个问题不是什么“结束”的意思很清楚,在这里做。
我面临着同样的挑战,这里是我的简单的方法。这个工作没有问题。
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;
}
));
}
}
在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
}
}
作为异步扩展方法。从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
}