You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DataGrid文本框:数字输入限制+空白自动填充默认值0的问题排查

问题描述

我在DataGrid的数据模板中使用TextBox绑定了Price字段(数据从文件加载),需要实现两个功能:

  1. 限制用户仅能输入带小数点的数字
  2. 不允许单元格为空,空白时自动填充默认值0
    我尝试用TextChanged和TouchLeave事件处理,但均未生效,想知道错误原因、修复方法以及应该使用哪个事件。

原XAML代码:

<DataGridTemplateColumn Header="Price" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
    <TextBox Text="{Binding Price}"  PreviewTextInput="OnPreviewTextInput" 
             PreviewKeyDown="TextBox_PreviewKeyDown" 
             TextChanged="TextBox_TextChanged" TouchLeave="TextBox_TouchLeave"    />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

原后台代码:

private void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
string CultureName = Thread.CurrentThread.CurrentCulture.Name;
CultureInfo ci = new CultureInfo(CultureName);
ci.NumberFormat.NumberDecimalSeparator = ".";
Thread.CurrentThread.CurrentCulture = ci;

string input = ((TextBox)sender).Text + e.Text;

string pattern = "^[0-9]+[" + ci.NumberFormat.NumberDecimalSeparator + "]?([0-9]+)?$";

Regex regex = new Regex(pattern);
e.Handled = !regex.IsMatch(input);

}

private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
// Prohibit space
if (e.Key == Key.Space)
    e.Handled = true;
}

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (string.IsNullOrEmpty(e.ToString()))
{
    e.Handled = true;
    ((TextBox)sender).Text  = 0.ToString();

}

}

private void TextBox_TouchLeave(object sender, TouchEventArgs e)
{
if (string.IsNullOrEmpty(e.ToString()))
{
    e.Handled = true;
    ((TextBox)sender).Text = 0.ToString();

}
}

错误原因

  1. TextChanged事件逻辑错误:判断空值时用string.IsNullOrEmpty(e.ToString()),实际是检查事件参数的字符串表示,而非TextBox的真实文本,导致填充0的逻辑永远不会触发;另外直接修改Text属性会再次触发TextChanged,可能引发循环调用。
  2. TouchLeave事件场景局限:该事件仅在触摸设备上用户离开控件时触发,PC端鼠标操作完全不会触发,且同样错误地判断事件参数而非文本内容。
  3. 绑定配置缺失:Text绑定未设置UpdateSourceTrigger,默认是LostFocus,数据更新不及时;若Price是数值类型,空文本会导致绑定失败,无法同步值到数据源。

修复方案

1. 选择合适的事件

推荐使用LostFocus事件,它能覆盖鼠标、键盘、触摸所有操作场景,配合PreviewTextInput做输入限制,同时优化绑定配置。

2. 修改XAML代码

添加绑定的UpdateSourceTrigger=PropertyChanged,并替换TouchLeave为LostFocus:

<DataGridTemplateColumn Header="Price" Width="100">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBox Text="{Binding Price, UpdateSourceTrigger=PropertyChanged}" 
                     PreviewTextInput="OnPreviewTextInput" 
                     PreviewKeyDown="TextBox_PreviewKeyDown" 
                     LostFocus="TextBox_LostFocus"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

3. 修改后台代码

输入限制逻辑优化(解决多小数点问题)

原正则允许多个小数点(如12..3),修正后确保仅能输入一个小数点:

private void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
    var textBox = sender as TextBox;
    if (textBox == null) return;

    string decimalSeparator = ".";
    // 拼接选中区域替换后的完整文本,更准确
    string fullText = textBox.Text.Remove(textBox.SelectionStart, textBox.SelectionLength)
                                 .Insert(textBox.SelectionStart, e.Text);

    // 禁止以小数点开头
    if (fullText.StartsWith(decimalSeparator))
    {
        e.Handled = true;
        return;
    }
    // 限制仅能有一个小数点
    if (fullText.Count(c => c == decimalSeparator[0]) > 1)
    {
        e.Handled = true;
        return;
    }

    // 正则匹配:允许整数或带一个小数点的小数
    Regex regex = new Regex($"^[0-9]*{decimalSeparator}?[0-9]*$");
    e.Handled = !regex.IsMatch(fullText);
}

空值处理逻辑(LostFocus事件)

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    var textBox = sender as TextBox;
    if (textBox == null) return;

    // 去除前后空白后判断是否为空
    if (string.IsNullOrWhiteSpace(textBox.Text))
    {
        textBox.Text = "0";
        // 手动更新绑定源,确保数据同步到Price属性
        BindingExpression binding = textBox.GetBindingExpression(TextBox.TextProperty);
        binding?.UpdateSource();
    }
}

private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Space)
        e.Handled = true;
}

4. 额外建议(可选)

如果Price是数值类型(如double),可添加绑定验证避免空文本导致的绑定错误:

<TextBox Text="{Binding Price, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" 
         .../>

随后在ViewModel的Price属性中实现验证逻辑,或通过IDataErrorInfo接口完成数据验证。


内容的提问来源于stack exchange,提问作者user838691

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 21:40:20