关于 c#:TextBox 货币格式,带 1 个逗号

TextBox money format with 1 comma

我在 c# winforms 中有一个文本框。

1
2
3
4
5
6
7
8
9
10
   private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (!char.IsNumber(e.KeyChar) & (Keys)e.KeyChar != Keys.Back
                & e.KeyChar != ',')
        {
            e.Handled = true;
        }

        base.OnKeyPress(e);
    }

上面的代码效果很好,但是我可以添加 2 个逗号,例如"100,,00"。我怎样才能让用户添加"100,00"或"100,000,000"和 1 个逗号作为货币格式?

任何帮助将不胜感激。

谢谢。


不是对您的实际问题的直接回答,但绝对是您应该考虑的建议:为此使用 MaskedTextBox,而不是 TextBox

MaskedTextBox 有一个 Mask 属性,它充当文本值的模式。在您的情况下,适当的掩码可能是 #,###.##。请注意,根据文化,您的程序集在小数点分隔符上可能不是逗号。不过,您仍然可以将其转换为数值,这肯定是您想要的。

更新:

作为附加建议,一些 3rd 方 vendor(如 devexpress)确实提供了具有更高级掩码输入的控件,这些掩码输入可以使用传统掩码以及基于正则表达式的验证器。如果你能负担得起这笔钱,它可能是值得研究的。


正如 Crono 在另一个答案中所说,a MaskedTextBox 是最好的解决方案。但是,如果您真的想在文本框中添加约束和格式,您可以将文本解析为 decimal,然后完全覆盖逗号键并且只允许一位小数。

这有点被破解了,但应该可以实现你想要的:

首先创建不允许逗号输入的事件处理程序,只允许一个小数点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        //Just don't let them type commas - We will format after the TextBox is left
        if (!char.IsControl(e.KeyChar)
            && !char.IsDigit(e.KeyChar)
            && e.KeyChar == ',')
        {
            e.Handled = true;
        }

        // only allow one decimal point
        if (e.KeyChar == '.'
            && (sender as TextBox).Text.IndexOf('.') > -1)
        {
            e.Handled = true;
        }
    }

然后创建一个小助手方法来将 TextBox 的值解析为 decimal

1
2
3
4
5
6
7
    private decimal GetValueFromTextBox(string input)
    {
        input = System.Text.RegularExpressions.Regex.Replace(input, @"[,$%]", String.Empty);
        //Could use Try parse here for better handling
        decimal output = Convert.ToDecimal(input);
        return output;
    }

然后从你的 TextBox_Leave 事件中调用函数:

1
2
3
4
5
6
    private void textBox1_Leave(object sender, EventArgs e)
    {
        var value = GetValueFromTextBox(textBox1.Text);

        textBox1.Text = value.ToString("c");
    }

这会将值格式化为货币格式,并使用适当的逗号放置,也只强制保留一位小数。再次不是最好的解决方案(使用 MaskedTextBox),但它适用于普通 TextBox 控件。


您可以使用 NumericUpDown 控件来避免对数字进行任何手动验证。


我建议检查 3rd 方控件。他们节省了大量时间(这是金钱)和头痛。 DevExpress TextEdit 控件执行此操作……这是一个简单的选项,完全不需要时间来设置。我假设所有其他人(Telerik、Infragistics 等)也这样做。


你可以使用像 [\\\\d]*,[\\\\d]* 这样的正则表达式来确保它只匹配数字之间最多有一个逗号的约束。

更新:大致如下:

1
2
3
4
5
6
7
8
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    var newString = textBox1.Text += e.KeyChar;
    if(!Regex.IsMatch(newString,"[\\d]*,[\\d]*"))
        e.Handled = true;

    base.OnKeyPress(e);
}


您可以通过使用 MaskedTextBox,

来限制文本框中允许的输入

如果您更喜欢逻辑/手动测试,请添加以下内容:!textBox1.Text.Contains(',')

只有当文本框中还没有逗号时才会返回 true。

编辑:实际上,我不确定新添加的逗号是否会包含在按键事件之前或之后 - 如果包含,那么您可能必须使用 count 代替:

1
2
3
4
if( ... && (textBox1.Text.Count(c => c == ',') <= 1) )
{
    ....
}

PS:我会重构这段代码并将测试移到单独的方法中以保持清洁,所以主要测试看起来像这样:

1
2
3
if(IsValidChar(e.KeyChar) && IsOnlyOneCommaProvided()){
    ...
}

javascript解决方案怎么样?

它受益于独立于平台,并负责文本字段中的光标位置,加上服务器端没有处理,这总是很好。

一个缺点是如果 JS 被禁用,另一个你必须在提交时在服务器端"清理"逗号值。我认为它是更优雅的解决方案。

只需添加到您的文本框 type='tel' 属性,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<input type='tel' />



<script type="text/javascript">
    $(function () {
        $("[type='tel']").keydown(function (event) {
            var position = this.selectionStart;
            var $this = $(this);
            var val = $this.val();
            if (position == this.selectionEnd &&
                ((event.keyCode == 8 && val.charAt(position - 1) =="," && val.substr(0, position - 1).indexOf(".") == -1)
                || (event.keyCode == 46 && val.charAt(position) =="," && val.substr(0, position).indexOf(".") == -1))) {
                event.preventDefault();
                if (event.keyCode == 8) {
                    $this.val(val.substr(0, position - 2) + val.substr(position));
                    position = position - 2;
                } else {
                    $this.val(val.substr(0, position) + val.substr(position + 2));
                }
                $this.trigger('keyup', { position: position });
            } else {
                this.dispatchEvent(event);
            }
        });

                $("[type='tel']").keyup(function(event, args) {
                        if (event.which >= 37 && event.which <= 40) {
                                event.preventDefault();
                        }

                        var position = args ? args.position : this.selectionStart;
                        var $this = $(this);
                        var val = $this.val();
                        var parts =val.split(".");
                    var valOverDecimalPart = parts[0];
                        var commaCountBefore = valOverDecimalPart.match(/,/g) ? valOverDecimalPart.match(/,/g).length : 0;
                        var num = valOverDecimalPart.replace(/[^0-9]/g, '');
                        var result = parts.length == 1 ? num.replace(/(\\d)(?=(\\d{3})+(?!\\d))/g,"$1,") : num.replace(/(\\d)(?=(\\d{3})+(?!\\d))/g,"$1,") +"."+ parts[1].replace(/[^0-9.]/g,"");
                    $this.val(result);
                    var commaCountAfter = $this.val().match(/,/g) ? $this.val().match(/,/g).length : 0;
                        position = position + (commaCountAfter - commaCountBefore);
                        this.setSelectionRange(position, position);
                });
            });