我正在尝试使用TextBox
将double
绑定到某个对象的UpdateSourceTrigger=PropertyChanged
属性。目标是在编辑期间立即验证输入的值是否在允许的范围内(如果没有则显示错误)。我想在模型级别上实现验证,即通过IDataErrorInfo
。
当我绑定到int属性时,所有工作都很好,但如果属性为double,则会出现令人沮丧的编辑行为:在删除数字的小数部分中的最后一个有效数字后 - 小数分隔符将自动擦除(包含所有可能的小数零)。例如,在从数字'12 .03'中删除数字'3'后,文本将更改为'12'而不是'12 .0'。
请帮助。
以下是示例代码:
MainWindow.xaml:
<Window x:Class="BindWithValidation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="80" Width="200" WindowStartupLocation="CenterOwner">
<StackPanel>
<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
</Window>
MainWindow.xaml.cs:
namespace BindWithValidation
{
public partial class MainWindow : Window
{
private UISimpleData _uiData = new UISimpleData();
public MainWindow()
{
InitializeComponent();
DataContext = _uiData;
}
}
}
UISimpleData.cs:
namespace BindWithValidation
{
public class UISimpleData : INotifyPropertyChanged, IDataErrorInfo
{
private double _doubleField = 12.03;
public double DoubleField
{
get
{
return _doubleField;
}
set
{
if (_doubleField == value)
return;
_doubleField = value;
RaisePropertyChanged("DoubleField");
}
}
public string this[string propertyName]
{
get
{
string validationResult = null;
switch (propertyName)
{
case "DoubleField":
{
if (DoubleField < 2 || DoubleField > 5)
validationResult = "DoubleField is out of range";
break;
}
default:
throw new ApplicationException("Unknown Property being validated on UIData");
}
return validationResult;
}
}
public string Error { get { return "not implemented"; } }
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string property)
{
if ( PropertyChanged != null )
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
答案 0 :(得分:10)
我意识到我参加派对的时间有点晚了,但我找到了一个(我认为)这个问题的相当干净的解决方案。
一个聪明的转换器,它记住转换为double的最后一个字符串,如果它存在则返回它应该做你想要的一切。
请注意,当用户更改文本框的内容时,ConvertBack将存储用户输入的字符串,解析字符串以获取double,并将该值传递给视图模型。紧接着,调用Convert来显示新更改的值。此时,存储的字符串不为空,将返回。
如果应用程序而不是用户导致double更改,则仅调用Convert。这意味着缓存的字符串将为null,并且将在double上调用标准的ToString()。
通过这种方式,用户在修改文本框的内容时可以避免出现奇怪的意外,但应用程序仍然可以触发更改。
public class DoubleToPersistantStringConverter : IValueConverter
{
private string lastConvertBackString;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is double)) return null;
var stringValue = lastConvertBackString ?? value.ToString();
lastConvertBackString = null;
return stringValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is string)) return null;
double result;
if (double.TryParse((string)value, out result))
{
lastConvertBackString = (string)value;
return result;
}
return null;
}
}
答案 1 :(得分:9)
将浮点值绑定到文本框的行为已更改 从.NET 4到4.5。使用.NET 4.5,不再可以输入 带有'UpdateSourceTrigger =的分隔符(逗号或点) PropertyChanged'默认为。
微软说,这是(<)>
如果您仍想使用'UpdateSourceTrigger = PropertyChanged',那么 可以通过添加强制.NET 4.5应用程序中的.NET 4行为 以下代码行到
App.xaml.cs
的构造函数:public App() { System.Windows.FrameworkCompatibilityPreferences .KeepTextBoxDisplaySynchronizedWithTextProperty = false; }
(塞巴斯蒂安·勒克斯 - 从here逐字复制)
答案 2 :(得分:4)
尝试使用小数位格式化值?
虽然你可能总是有N个小数位,但这可能很奇怪。
<TextBox.Text>
<Binding Path="DoubleField" StringFormat="{}{0:0.00}" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True"/>
</TextBox.Text>
如果固定的小数位数不够好,您可能必须编写一个转换器,将该值视为字符串并将其转换回double。
答案 3 :(得分:4)
问题是每次值更改时都要更新属性。当您将12.03更改为12.0时,它将舍入为12。
您可以通过更改delay
中的TextBox
来提供xaml
来查看更改
<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged,Delay=500, ValidatesOnDataErrors=True}">
但是delay
会在mili sec的延迟时间之后通知并设置属性。
最好像这样使用StringFormat
<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged,StringFormat=N2, ValidatesOnDataErrors=True}">
答案 4 :(得分:2)
我遇到了同样的问题,并找到了一个非常简单的解决方案:使用自定义验证器,当文本以“。”结尾时,它不会返回“有效”。或“0”:
double val = 0;
string tmp = value.ToString();
if (tmp.EndsWith(",") || tmp.EndsWith("0") || tmp.EndsWith("."))
{
return new ValidationResult(false, "Enter another digit, or delete the last one.");
}
else
{
return ValidationResult.ValidResult;
}
答案 5 :(得分:1)
尝试在绑定上使用StringFormat:
<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, StringFormat='0.0'}">
不确定该字符串格式是否正确,因为我暂时没有完成,但这只是一个例子