如何在Silverlight中创建数字文本框?

12

如标题所述。 我看过从TextBox继承的方法,但唯一明智的重载是"OnKeyDown",但它只给了我一个来自Key枚举的键(没有使用Char.IsNumeric()的方法)。

11个回答

9

我采纳了Nidhal的建议答案,并稍作修改以处理数字上方字符的移位情况(即!@#$ %^&*()),因为该解决方案仍将允许这些字符出现在文本框中。

private void NumClient_KeyDown(object sender, KeyEventArgs e)
{       
    // Handle Shift case
    if (Keyboard.Modifiers == ModifierKeys.Shift)
    {
       e.Handled = true;
    }

    // Handle all other cases
    if (!e.Handled && (e.Key < Key.D0 || e.Key > Key.D9))
    {
        if (e.Key < Key.NumPad0 || e.Key > Key.NumPad9)
        {
            if (e.Key != Key.Back)
            {
                e.Handled = true;
            }
        }
    }           
}

2
这也会吞噬Tab和Shift-Tab键。 - Lucas B
你会如何在MVVM中实现这个? - user20358

7
访问http://www.dataartist.net/blog/post/Silverlight-Behavior-Modifications-13-NumericOnlyBehavior.aspx或按照以下方式使用TextBox行为。
  using System;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Input;
  using System.Windows.Interactivity;

  namespace DataArtist
  {
public class NumericOnly : Behavior<TextBox>
{
    private string Text { get; set; }
    private bool shiftKey;
    public bool StripOnExit { get; set; }

    public NumericOnly()
    {
        StripOnExit = false;
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.KeyDown += KeyDown;
        AssociatedObject.KeyUp += KeyUp;
        AssociatedObject.GotFocus += GotFocus;
        AssociatedObject.LostFocus += LostFocus;
    }

    void KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Shift)
        {
            shiftKey = false;
        }
    }

    void KeyDown(object sender, KeyEventArgs e)
    {
        if (StripOnExit != false || e.Key == Key.Tab || e.Key == Key.Enter)
        {
            return;
        }

        if (e.Key == Key.Shift)
        {
            shiftKey = true;
        }
        else
        {
            if (IsNumericKey(e.Key) == false)
            {
                e.Handled = true;
            }
        }
    }

    void GotFocus(object sender, RoutedEventArgs e)
    {
        Text = AssociatedObject.Text;
    }

    private void LostFocus(object sender, RoutedEventArgs e)
    {
        if (AssociatedObject.Text == Text)
        {
            return;
        }

        string content = string.Empty;

        foreach (var c in AssociatedObject.Text)
        {
            if (Char.IsNumber(c) == true)
            {
                content += c;
            }
        }

        AssociatedObject.Text = content;
    }

    public bool IsNumericKey(Key key)
    {
        if (shiftKey == true)
        {
            return false;
        }

        string code = key.ToString().Replace("NumPad", "D");

        if (code[0] == 'D' && code.Length > 1)
        {
            return (Char.IsNumber(code[1]));
        }

        return false;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.KeyDown -= KeyDown;
        AssociatedObject.LostFocus -= LostFocus;
        AssociatedObject.GotFocus -= GotFocus;
    }
}   
    }

行为肯定是正确的选择。 它也比附加属性更容易清除。(将附加到KeyUp和KeyDown处理程序的附加属性很有可能创建GC根并防止垃圾回收。可以修改该行为,使所有事件处理程序都在Loaded事件中添加,然后在Unloaded事件中取消挂钩。) - Mike Post

6
private void Numclient_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key < Key.D0 || e.Key > Key.D9)
    {
        if (e.Key < Key.NumPad0 || e.Key > Key.NumPad9)
        {
            if (e.Key != Key.Back && e.Key != Key.Shift)
            {
                e.Handled = true;
            }
        }
    }
}

amurra的编辑对此进行了改进,请使用它:https://dev59.com/qXVC5IYBdhLWcg3whRcw#1469073 - Lucas B

5

请查看工具包中的NumericUpDown控件http://codeplex.com/Silverlight,也许您可以使用该控件,或查看源代码来实现自己的数字文本框。


1
NumericUpDown只有一个问题。例如,如果您在其中输入值999并使用退格键清除输入,则会失去焦点,并将其设置回999而不是设置为0。 - Rumplin
你为什么认为这是一个问题? =)) - Valentin Kuzub

4

你的链接似乎已经失效了。 - Robert Jørgensgaard Engdahl

2
    private void TextBox_KeyDown(object sender, KeyEventArgs e)
    {
        bool isDigit = e.Key >= Key.D0 && e.Key < Key.D9 || e.Key == Key.NumPad0 || e.Key == Key.NumPad1 || e.Key == Key.NumPad2 || e.Key == Key.NumPad3 || e.Key == Key.NumPad4 || e.Key == Key.NumPad5 || e.Key == Key.NumPad6 ||
        e.Key == Key.NumPad7 || e.Key == Key.NumPad8 || e.Key == Key.NumPad9 ||e.Key == Key.Back || e.Key == Key.Delete || e.Key == Key.Left || e.Key == Key.Right;

        if (isDigit) { }
        else
            e.Handled = true; 
    }

1
private void txtbox_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.D0 || e.Key == Key.D1 || e.Key == Key.D2 || e.Key == Key.D3 || e.Key == Key.D4 || e.Key == Key.D5 || e.Key == Key.D6 || e.Key == Key.D7 || e.Key == Key.D8 || e.Key == Key.D9 || e.Key == Key.NumPad0 || e.Key == Key.NumPad1 || e.Key == Key.NumPad2 || e.Key == Key.NumPad3 || e.Key == Key.NumPad4 || e.Key == Key.NumPad5 || e.Key == Key.NumPad6 || e.Key == Key.NumPad7 || e.Key == Key.NumPad8 || e.Key == Key.NumPad9)
        e.Handled = false;
    else
        e.Handled = true;
}

1

它有效:

static bool AltGrIsPressed;

void Numclient_KeyUp(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Alt)
    {
        AltGrIsPressed = false;
    }
}

void Numclient_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Alt)
    {
        AltGrIsPressed = true;
    }

    if (Keyboard.Modifiers == ModifierKeys.Shift || AltGrIsPressed == true)
    {
        e.Handled = true;
    }

    if (e.Handled == false && (e.Key < Key.D0 || e.Key > Key.D9))
    {
        if (e.Key < Key.NumPad0 || e.Key > Key.NumPad9)
        {
            if (e.Key != Key.Back)
            {
                e.Handled = true;
            }
        }
    }       
}

1

我知道这个问题已经有答案了,但是我没有找到一个能够处理所有特殊情况的合适解决方案,大多数答案都忽略了一些重要的按键,比如Home、End、Tab、Shift+任何按键等等。

因此,我开发了自己的实现,希望能对某些人有所帮助!

public class IntegerTextBox : TextBox
    {
        /// <summary>
        /// To be raised whenever integer value changed
        /// </summary>
        public event EventHandler ValueChanged;

        /// <summary>
        /// To restore if the user entered invalid characters
        /// </summary>
        private int lastSavedValue = 0;

        private int lastSelectionStart = 0;
        private int lastSelectionLength = 0;


        public int IntegerValue
        {
            get
            {
                //the default value is 0 if there is no text in the textbox
                int value = 0;
                int.TryParse(Text, out value);
                return value;
            }
            set
            {
                if (this.Text.Trim() != value.ToString())
                {
                    Text = value.ToString();
                }
            }
        }

        public IntegerTextBox()
            : base()
        {
            this.LostFocus += (sender, e) =>
                {
                    //if the user clears the text the text box and leaves it, set it to default value
                    if (string.IsNullOrWhiteSpace(this.Text))
                        IntegerValue = 0;
                };
            this.Loaded += (sender, e) =>
                {
                    //populate the textbox with Initial IntegerValue (default = 0)
                    this.Text = this.IntegerValue.ToString();
                };

            this.TextChanged += (sender, e) =>
                {
                    int newValue = 0;
                    if (int.TryParse(this.Text, out newValue)) //this will handle most cases like number exceeds the int max limits, negative numbers, ...etc.
                    {
                        if (string.IsNullOrWhiteSpace(Text) || lastSavedValue != newValue)
                        {
                            lastSavedValue = newValue;
                            //raise the event
                            EventHandler handler = ValueChanged;
                            if (handler != null)
                                handler(this, EventArgs.Empty);

                        }
                    }
                    else 
                    {
                        //restore previous number
                        this.Text = lastSavedValue.ToString();
                        //restore selected text
                        this.SelectionStart = lastSelectionStart;
                        this.SelectionLength = lastSelectionLength;
                    }
                };

            this.KeyDown += (sender, e) =>
                {
                    //before every key press, save selection start and length to handle overwriting selected numbers
                    lastSelectionStart = this.SelectionStart;
                    lastSelectionLength = this.SelectionLength;
                };
        }
    } 

上述代码有一个缺点,TextChanged事件会频繁触发,但由于我们需要一个整数文本框,因此我们可以依赖ValueChanged事件!


0

扩展普通的Silverlight文本框控件。将此代码添加到扩展的TextBox类中:

string nums = "1234567890";
string lastText = "";
int lastSelStart = 0;

protected override void TextChanged(object sender, TextChangedEventArgs e)
{
    if(!nums.Contains(this.Text.Substring(this.Text.Length -1)))
    {
         this.Text = lastText;
         this.SelectionStart = lastSelStart;
         return;
    }

    lastText = this.Text;
    lastSelStart = this.SelectionStart;

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接