65.9K
CodeProject 正在变化。 阅读更多。
Home

自定义 WPF TextBox, 允许基于数据类型或正则表达式的输入

starIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

1.00/5 (1投票)

2012 年 1 月 4 日

CPOL

2分钟阅读

viewsIcon

25231

downloadIcon

688

扩展 WPF TextBox,仅允许输入数字(用于 int 和 float)和正则表达式。

引言

本文档描述了如何创建一个自定义 WPF TextBox 控件,该控件仅允许用户输入基于数据类型允许的字符。例如,对于 int 数据类型,仅允许输入数字字符。此外,还具有定义 TextBox 正则表达式掩码的功能。

使用代码

首先,我们需要创建一个依赖属性,该属性将允许我们设置数据类型。

public static DependencyProperty DataTypeProperty = DependencyProperty.Register("DataType", 
       typeof(string), typeof(MaskTextBox), new PropertyMetadata("string"));

public string DataType
{
    get { return (string)GetValue(DataTypeProperty); }
    set { SetValue(DataTypeProperty, value); }
}
...

在本示例中,我们使用了三种数据类型:intfloatRegEx。对于 RegEx,我们还需要另一个名为 RegEx 的依赖属性,该属性将使我们能够指定正则表达式。

public static DependencyProperty RegExProperty = DependencyProperty.Register("RegEx", 
       typeof(string), typeof(MaskTextBox), new PropertyMetadata("string"));
public string RegEx
{
    get { return (string)GetValue(RegExProperty); }
    set { SetValue(RegExProperty, value); }
}
...

接下来,我们编写一个方法来根据数据类型验证输入。此方法使用 TryParse 方法来验证 intfloat 数据类型。对于 RegEx,我们使用 IsMatch 方法来使用 Regex 属性中指定的正则表达式验证输入。此方法主要用于将数据粘贴到 TextBox 中时使用。

private Boolean IsDataValid(IDataObject data)
{
    Boolean isValid = false;
    if (data != null)
    {
        String text = data.GetData(DataFormats.Text) as String;
        if (!String.IsNullOrEmpty(text == null ? null : text.Trim()))
        {
            switch (DataType)
            {
                case "INT":
                    Int32 result = -1;
                    if (Int32.TryParse(text.Trim(), out result))
                    {
                        if (result > 0)
                        {
                            isValid = true;
                        }
                    }
                    break;

                case "FLOAT":
                    float floatResult = -1;
                    if (float.TryParse(text.Trim(), out floatResult))
                    {
                        if (floatResult > 0)
                        {
                            isValid = true;
                        }
                    }
                    break;
                case "RegEx":
                    if (System.Text.RegularExpressions.Regex.IsMatch(text, RegEx))
                    {
                        isValid = true;
                    }
                    break;
            }
        }
    }
    return isValid;
}

protected override void OnDrop(DragEventArgs e)
{
    e.Handled = !IsDataValid(e.Data);
    base.OnDrop(e);
}

protected override void OnDragOver(DragEventArgs e)
{
    if (!IsDataValid(e.Data))
    {
        e.Handled = true;
        e.Effects = DragDropEffects.None;
    }
    base.OnDragEnter(e);
}

EventManager.RegisterClassHandler(
        typeof(MaskTextBox),
        DataObject.PastingEvent,
        (DataObjectPastingEventHandler)((sender, e) =>
                         {
                             if (!IsDataValid(e.DataObject))
                             {
                                 DataObject data = new DataObject();
                                 data.SetText(String.Empty);
                                 e.DataObject = data;
                                 e.Handled = false;
                             }
                         }));
...

我们还需要限制用户输入无效字符。为此,我们重写 WPF TextBox 的 OnPreviewTextInput 方法。在此方法中,我们通过在光标索引处插入新字符来生成最终文本。这确保了即使用户在现有字符之间或开头输入新字符,验证也不会失败。接下来,根据指定的数据类型验证文本。如果验证失败,则将 e.Handled 设置为 true,并且将取消用户操作。

string text = this.Text;
text = text.Insert(this.CaretIndex, e.Text);
switch (DataType)
{
    case "INT":
        Int32 result = -1;
        if (!Int32.TryParse(text.Trim(), out result))
        {
            if (!text.Equals("-"))
                e.Handled = true;
        }
        break;

    case "FLOAT":
        float floatResult = -1;
        if (!float.TryParse(text.Trim(), out floatResult))
        {
            if (!text.Equals("-"))
                e.Handled = true;
        }
        break;
    case "RegEx":
        if (!System.Text.RegularExpressions.Regex.IsMatch(text, RegEx))
        {
            e.Handled = true;
        }
        break;
}
...

请注意,在上面的代码中,对于情况“INT”和“FLOAT”,存在一个 if 条件。这是因为对于数据类型 int,如果用户要输入 -5,用户将键入的第一个字符是“-”。但是,方法 Int32.TryParse 对于“-”将返回 false。因此需要进行检查,以防止验证失败。

我们还需要确保用户不要在 TextBox 中仅输入“-”号。为此,我们可以将处理程序添加到 TextBox 的 LostFocusEvent。因此,每当 TextBox 失去焦点时,将验证文本,如果仅为“-”,则清除文本。

this.AddHandler(MaskTextBox.LostFocusEvent, new RoutedEventHandler(LostFocusEventHandler));
public void LostFocusEventHandler(object sender, RoutedEventArgs e)
{
    if (this.Text == "-")
        this.Text = string.Empty;
}
...

此外,Int32.TryParse 不会在用户输入空格时使验证失败。我们可以在 TextBox 的 PreviewKeyDownEvent 中处理此问题,如果输入空格,则设置 e.Handled = true

this.AddHandler(MaskTextBox.PreviewKeyDownEvent, 
                new RoutedEventHandler(PreviewKeyDownEventHandler));
public void PreviewKeyDownEventHandler(object sender, RoutedEventArgs e)
{
    KeyEventArgs ke = e as KeyEventArgs;
    if (ke.Key == Key.Space)
    {
        ke.Handled = true;
    }
}
...
© . All rights reserved.