UWP中decimal属性双向绑定异常的原因及解决方法
这个问题的核心在于类型转换兼容性问题:TextBox的Text属性是string类型,而你的TG属性是decimal类型。双向绑定需要在string和decimal之间完成双向转换,虽然.NET/UWP的绑定系统自带了一些默认类型转换器,但decimal的转换逻辑对输入格式要求更严格——比如系统文化使用逗号作为小数点分隔符,但用户输入了点,或者输入了非数字字符时,默认转换器就会触发报错,无法完成从目标(TextBox文本)到源(decimal属性)的回写。而double的默认转换器容错性相对更高,所以改成double后能正常工作。
另外还要注意:你代码里的TG属性setter没有触发PropertyChanged事件,即使转换成功,UI也无法及时感知到属性值的变化,这可能会带来后续的同步问题。
下面提供几种可行的解决办法,按推荐程度排序:
1. 自定义值转换器(最灵活可靠)
写一个实现IValueConverter接口的转换器,手动处理string和decimal之间的双向转换,还能处理空值、格式错误等边界情况:
public class DecimalToStringConverter : IValueConverter { // 从源(decimal)到目标(string)的转换 public object Convert(object value, Type targetType, object parameter, string language) { if (value is decimal decimalValue) { return decimalValue.ToString(CultureInfo.CurrentCulture); } return string.Empty; } // 从目标(string)到源(decimal)的转换 public object ConvertBack(object value, Type targetType, object parameter, string language) { if (string.IsNullOrWhiteSpace(value?.ToString())) { return 0m; // 也可以返回null,根据你的业务需求调整 } if (decimal.TryParse(value.ToString(), NumberStyles.Number, CultureInfo.CurrentCulture, out decimal result)) { return result; } // 转换失败时返回UnsetValue,让绑定保留原有值 return DependencyProperty.UnsetValue; } }
然后在XAML的资源里声明这个转换器:
<Page.Resources> <local:DecimalToStringConverter x:Key="DecimalToStringConverter"/> </Page.Resources>
修改绑定使用这个转换器:
<TextBox Header="TG" HorizontalAlignment="Left" Margin="145,416,0,0" VerticalAlignment="Top" Width="224" Text="{Binding Path=Pessoa.Propriedades.TG, Mode=TwoWay, Converter={StaticResource DecimalToStringConverter}}" />
2. 配置绑定的格式和文化
如果不想写自定义转换器,可以在绑定里指定StringFormat和ConverterCulture,确保输入输出的格式和系统文化匹配:
<TextBox Header="TG" HorizontalAlignment="Left" Margin="145,416,0,0" VerticalAlignment="Top" Width="224" Text="{Binding Path=Pessoa.Propriedades.TG, Mode=TwoWay, StringFormat={}{0:N}, ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}}" />
注意:需要在XAML头部引入命名空间xmlns:gl="clr-namespace:System.Globalization;assembly=mscorlib"
这种方法的局限性是没法处理格式错误的输入,用户输入非法字符时还是会触发绑定报错。
3. 修正属性的INotifyPropertyChanged实现
最后别忘了完善TG属性的setter,触发PropertyChanged事件,确保UI和数据源同步:
private decimal _tg; public decimal TG { get => _tg; set { if (_tg != value) { _tg = value; OnPropertyChanged(nameof(TG)); } } } // 实现OnPropertyChanged辅助方法 protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
这样修改后,decimal类型的双向绑定就能正常工作,同时保证数值精度不受影响。
内容的提问来源于stack exchange,提问作者Tony

