我知道这是一个古老的问题,有很多答案,但是我还没有找到任何好的,可靠的答案.
要求是一个文本框,该文本框将始终包含Double.TryParse将在其上返回true的字符串.
我见过的大多数实现都不反对输入,例如:“ 10.45.8”.这是个问题.
最好的方法是完全使用事件,例如TextInput和KeyDown(用于空格).这些问题是要获得一个字符串,它表示更改之前的新文本(或更改之后的旧文本)非常复杂. TextChanged的问题在于它没有提供获取旧Text的方法.
如果您能以某种方式在更改之前获取新Text,那将是最有帮助的,因为您可以针对Double.TryParse对其进行测试.不过,可能会有更好的解决方案.
做这个的最好方式是什么?
对此问题的最佳答案是采用几种方法进行比较.
解决方法:
方法1
对TextBox使用TextChanged和KeyDown事件的组合.在KeyDown上,您可以将当前文本保存在文本框中,然后在TextChanged事件中执行Double.TryParse.如果输入的文本无效,那么您将还原为旧文本值.看起来像:
private int oldIndex = 0;
private string oldText = String.Empty;
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
double val;
if (!Double.TryParse(textBox1.Text, out val))
{
textBox1.TextChanged -= textBox1_TextChanged;
textBox1.Text = oldText;
textBox1.CaretIndex = oldIndex;
textBox1.TextChanged += textBox1_TextChanged;
}
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
oldIndex = textBox1.CaretIndex;
oldText = textBox1.Text;
}
CaratIndex有助于在验证失败时将光标移到第一个位置,不会使用户烦恼.但是,此方法不能捕获空格键.它将允许像“ 1234.56”这样输入文本.此外,粘贴文本将无法正确验证.除此之外,我不喜欢在文本更新过程中弄乱事件处理程序.
方法2
这种方法应该可以满足您的需求.
使用PreviewKeyDown和PreviewTextInput事件处理程序.通过观看这些事件并进行相应的处理,您无需担心在文本框中恢复为先前的文本值. PreviewKeyDown可用于监视和忽略您的SpaceBar键,PreviewTextInput可用于在分配新的文本框值之前对其进行测试.
private void textBox1_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Space)
{
e.Handled = true;
}
}
private void textBox1_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
//Create a string combining the text to be entered with what is already there.
//Being careful of new text positioning here, though it isn't truly necessary for validation of number format.
int cursorPos = textBox1.CaretIndex;
string nextText;
if (cursorPos > 0)
{
nextText = textBox1.Text.Substring(0, cursorPos) + e.Text + textBox1.Text.Substring(cursorPos);
}
else
{
nextText = textBox1.Text + e.Text;
}
double testVal;
if (!Double.TryParse(nextText, out testVal))
{
e.Handled = true;
}
}
这种方法可以更好地捕获无效输入,然后再将其输入文本框.但是,我认为将事件设置为Handled可能会使您陷入麻烦,具体取决于消息路由列表中的其他目标.此处未处理的最后一项是用户将无效输入粘贴到文本框中的能力.可以通过添加此代码(从Paste Event in a WPF TextBox开始构建)来处理.
private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
double testVal;
bool ok = false;
var isText = e.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);
if (isText)
{
var text = e.SourceDataObject.GetData(DataFormats.Text) as string;
if (Double.TryParse(text, out testVal))
{
ok = true;
}
}
if (!ok)
{
e.CancelCommand();
}
}
在InitializeComponent调用之后,使用以下代码添加此处理程序:
DataObject.AddPastingHandler(textBox1, new DataObjectPastingEventHandler(OnPaste));