WPF中TextBox失去焦点时修改StringFormat以显示小数
实现TextBox失去焦点时才显示小数格式的方案
你的核心需求是让TextBox在**编辑状态(获得焦点)**时显示用户的原始输入,失去焦点后再以N2格式显示小数,同时允许输入为空。目前的绑定方式因为用了UpdateSourceTrigger=PropertyChanged和绑定内的StringFormat,导致输入过程中就会自动格式化,干扰编辑体验。下面是具体的解决步骤:
步骤1:创建焦点感知的格式转换器
我们需要一个转换器,根据TextBox的焦点状态动态切换显示格式。这个转换器会处理两种情况:
- 获得焦点:显示原始输入(如果是格式化后的小数,会自动还原成不带末尾零的数字字符串)
- 失去焦点:将有效数字格式化为
N2格式,无效输入/空值保持原样
创建一个实现IMultiValueConverter的转换器类:
using System; using System.Globalization; using System.Windows.Data; public class FocusDecimalFormatConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { // 确保输入参数正确 if (values.Length != 2 || values[0] is not string input) return values[0] ?? string.Empty; bool isFocused = (bool)values[1]; if (isFocused) { // 有焦点时,还原原始数字格式(去掉末尾的.00) if (decimal.TryParse(input, out decimal number)) { string rawNumber = number.ToString(); // 去掉末尾的零和可能的小数点 return rawNumber.TrimEnd('0').TrimEnd('.'); } return input; } else { // 失去焦点时,格式化为N2 if (decimal.TryParse(input, out decimal number)) { return number.ToString("N2", culture); } return input; } } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { // 将输入值直接返回给源属性,保持原始输入 return new object[] { value as string ?? string.Empty, Binding.DoNothing }; } }
步骤2:在XAML中声明转换器
在你的Window/UserControl的Resources里注册这个转换器:
<Window.Resources> <local:FocusDecimalFormatConverter x:Key="FocusDecimalFormatConverter"/> </Window.Resources>
注意:
local是你的转换器所在命名空间的前缀,需要根据实际情况调整。
步骤3:修改TextBox的绑定逻辑
移除原来绑定中的StringFormat和UpdateSourceTrigger=PropertyChanged,改用MultiBinding同时绑定AddItem属性和TextBox自身的IsFocused状态,并且设置UpdateSourceTrigger=LostFocus(确保只有失去焦点时才更新源):
<DataGridTemplateColumn Header="Add-Item" Width="2.25*"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBox Margin="6,5,4,5" helpers:TextBoxExtension.ValidationType="DecimalSpecialCharacter"> <TextBox.Text> <MultiBinding Converter="{StaticResource FocusDecimalFormatConverter}" Mode="TwoWay" UpdateSourceTrigger="LostFocus"> <Binding Path="AddItem" Mode="TwoWay"/> <Binding RelativeSource="{RelativeSource Self}" Path="IsFocused"/> </MultiBinding> </TextBox.Text> <i:Interaction.Triggers> <i:EventTrigger EventName="PreviewKeyUp" > <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}" /> </i:EventTrigger> </i:Interaction.Triggers> </TextBox> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
关键逻辑说明
- MultiBinding:同时传递
AddItem的值和TextBox的焦点状态给转换器,让转换器能动态判断显示格式。 - UpdateSourceTrigger=LostFocus:避免输入过程中频繁更新源属性,只有用户完成输入离开TextBox时才更新,保证编辑流畅。
- 转换器的处理:
- 编辑时:如果是格式化后的小数(比如
123.00),会自动还原为123,方便用户继续编辑。 - 失去焦点后:有效数字自动格式化为
N2(比如123变成123.00),空值或无效输入保持原样,符合你的需求。
- 编辑时:如果是格式化后的小数(比如
这样就能完美实现你想要的效果啦!
内容的提问来源于stack exchange,提问作者user3422209
相关产品推荐
相关产品推荐

