如何在WPF DataGrid中便捷设置并获取Decimal类型单元格新值?
WPF DataGrid Decimal类型单元格便捷小数输入方案
问题场景
将DataGrid单元格绑定到ViewModel的Decimal类型属性,已设置双向绑定和UpdateSourceTrigger=PropertyChanged,但输入小数时存在操作痛点:必须先输入整数部分,再返回添加小数点;直接输入小数点且无后续数字时,会被验证视为整数,操作繁琐。
解决方案
1. 自定义绑定转换器处理特殊输入
通过实现IValueConverter,在转换回源时处理纯小数点、空输入等特殊情况,避免验证失败:
public class DecimalInputConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value is decimal decimalValue ? decimalValue.ToString(culture) : string.Empty; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var input = value.ToString().Trim(); // 处理纯小数点,转换为0.0 if (input == ".") return 0.0m; // 处理空输入,返回0.0 if (string.IsNullOrEmpty(input)) return 0.0m; // 正常转换小数 if (decimal.TryParse(input, NumberStyles.Any, culture, out var result)) return result; // 转换失败时不更新源 return Binding.DoNothing; } }
在XAML中引用转换器:
<Window.Resources> <local:DecimalInputConverter x:Key="DecimalInputConverter"/> </Window.Resources> <DataGridTextColumn Header="Cantidad" Binding="{Binding Cantidad, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource DecimalInputConverter}}" IsReadOnly="false"/>
2. 使用自定义编辑模板(推荐)
替换默认的文本框编辑模板,使用带输入限制的TextBox或第三方掩码控件,提升输入体验:
方案A:自定义TextBox输入限制
<DataGridTemplateColumn Header="Cantidad"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Cantidad}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <TextBox Text="{Binding Cantidad, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" PreviewTextInput="DecimalTextBox_PreviewTextInput" DataObject.Pasting="DecimalTextBox_Pasting"/> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn>
后台代码处理输入验证:
private void DecimalTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e) { var textBox = sender as TextBox; // 只允许数字和单个小数点 if (!char.IsDigit(e.Text, 0) && e.Text != ".") { e.Handled = true; return; } if (e.Text == "." && textBox.Text.Contains(".")) { e.Handled = true; } } private void DecimalTextBox_Pasting(object sender, DataObjectPastingEventArgs e) { if (e.DataObject.GetDataPresent(typeof(string))) { var text = (string)e.DataObject.GetData(typeof(string)); if (!text.All(c => char.IsDigit(c) || c == ".") || text.Count(c => c == ".") > 1) { e.CancelCommand(); } } else { e.CancelCommand(); } }
方案B:使用第三方掩码控件(如Extended WPF Toolkit)
<DataGridTemplateColumn Header="Cantidad"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Cantidad}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <xctk:MaskedTextBox Mask="###0.##" Value="{Binding Cantidad, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ValueType="{x:Type system:Decimal}"/> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn>
3. 调整绑定更新触发时机
如果不需要实时更新ViewModel,可将UpdateSourceTrigger改为LostFocus,这样在编辑过程中纯小数点不会立刻触发源更新,直到单元格失去焦点再完成转换,避免中间状态的验证问题:
<DataGridTextColumn Header="Cantidad" Binding="{Binding Cantidad, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" IsReadOnly="false"/>
4. 自定义验证规则允许临时输入
添加自定义ValidationRule,允许空字符串或纯小数点作为临时输入,避免编辑过程中出现验证错误提示:
public class DecimalValidationRule : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { var input = value.ToString().Trim(); // 允许临时的空输入或纯小数点 if (string.IsNullOrEmpty(input) || input == ".") return ValidationResult.ValidResult; // 验证有效小数 return decimal.TryParse(input, out _) ? ValidationResult.ValidResult : new ValidationResult(false, "请输入有效的小数"); } }
XAML中绑定添加验证规则:
<DataGridTextColumn Header="Cantidad"> <DataGridTextColumn.Binding> <Binding Path="Cantidad" Mode="TwoWay" UpdateSourceTrigger=PropertyChanged> <Binding.ValidationRules> <local:DecimalValidationRule ValidationStep="RawProposedValue"/> </Binding.ValidationRules> </Binding> </DataGridTextColumn.Binding> </DataGridTextColumn>
内容的提问来源于stack exchange,提问作者Álvaro García
相关产品推荐
相关产品推荐

