我有一个示例,其中将视图模型的属性与一些TextBox控件(包括验证规则)绑定在一起.在大多数情况下,这可以正常工作.但是,当我尝试包括绑定的TextBox的IsFocused属性时,如果在控件中输入了无效的数字,就会遇到麻烦.
当我在直接绑定到视图模型属性的TextBox控件中输入错误的数字时,错误将按预期显示(TextBox周围的红色边框).但是,在与包含文本框的视图模型属性和IsFocused属性的MultiBinding绑定的TextBox中,不会显示错误,并且该值将重置为先前的有效值.
例如,如果小于10的数字无效,并且我输入3,则当TextBox失去焦点时,通常在TextBox中会出现一个红色边框,表示错误.但是在包含IsFocused作为其绑定源的TextBox中,该值将更改回之前的有效值(如果在我输入3之前有39,则TextBox会更改回39).
使用下面的代码,您可以重现该问题:
TestViewModel.cs
public class TestViewModel
{
public double? NullableValue { get; set; }
}
MainWindow.xaml
<Window x:Class="TestSO34204136TextBoxValidate.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:TestSO34204136TextBoxValidate"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:TestViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Nullable: "/>
<TextBox VerticalAlignment="Top" Grid.Column="1">
<TextBox.Text>
<MultiBinding Mode="TwoWay">
<Binding Path="NullableValue"/>
<Binding Path="IsFocused"
RelativeSource="{RelativeSource Self}"
Mode="OneWay"/>
<MultiBinding.ValidationRules>
<l:ValidateIsBiggerThanTen/>
</MultiBinding.ValidationRules>
<MultiBinding.Converter>
<l:TestMultiBindingConverter/>
</MultiBinding.Converter>
</MultiBinding>
</TextBox.Text>
</TextBox>
<TextBox VerticalAlignment="Top" Grid.Column="2"/>
</Grid>
</Window>
TestMultiBindingConverter.cs
public class TestMultiBindingConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] != null)
return values[0].ToString();
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
if (value != null)
{
double doubleValue;
var stringValue = value.ToString();
if (Double.TryParse(stringValue, out doubleValue))
{
object[] values = { doubleValue };
return values;
}
}
object[] values2 = { DependencyProperty.UnsetValue };
return values2;
}
}
ValidateIsBiggerThanTen.cs
public class ValidateIsBiggerThanTen : ValidationRule
{
private const string errorMessage = "The number must be bigger than 10";
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
var error = new ValidationResult(false, errorMessage);
if (value == null)
return new ValidationResult(true, null);
var stringValue = value.ToString();
double doubleValue;
if (!Double.TryParse(stringValue, out doubleValue))
return new ValidationResult(true, null);
if (doubleValue <= 10)
return error;
return new ValidationResult(true, null);
}
}
为什么在上面的示例中没有显示TextBox的错误?
解决方法:
您看到的行为的原因具体是您在MultiBinding中绑定了TextBox的IsFocused属性.当焦点改变时,这直接具有迫使更新绑定目标的效果.
在验证失败的情况下,会在很短的时间内触发验证规则,设置了错误,但是焦点实际上尚未更改.但这一切发生得太快,以至于用户看不到.而且由于验证失败,因此绑定源不会更新.
因此,当IsFocused属性值更改时,在对输入的值进行验证和拒绝后,接下来要发生的事情是重新评估绑定(因为源属性之一已更改!)以更新目标.并且由于实际源值从未更改,因此目标(文本框)将从您键入的内容恢复为源中存储的内容.
您应该如何解决?这取决于所需的确切行为.您有三个基本选项:
>保持对IsFocused的绑定,并添加UpdateSourceTrigger =“ PropertyChanged”.这将保持基本的当前行为,即失去焦点时将旧值复制回去,但至少会在编辑值时为用户提供立即的验证反馈.
>完全删除与IsFocused的绑定.这样,绑定的目标将不再依赖于此,并且在焦点更改时也不会重新评估.问题解决了.