- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个示例,其中我将视图模型的属性与某些TextBox
控件(包括验证规则)绑定在一起。在大多数情况下,这可以正常工作。但是,当我尝试包括绑定的IsFocused
的TextBox
属性时,在控件中输入无效数字的情况下,我遇到了麻烦。
当我在直接绑定到视图模型属性的TextBox
控件中输入错误的数字时,错误将按预期显示(TextBox
周围的红色边框)。但是在与TextBox
绑定的MultiBinding
中,该IsFocused
既包含视图模型属性又包含TextBox
的TextBox
属性,则不会显示错误,并且该值将重置为先前的有效值。
例如,如果小于10的数字无效,并且我输入3,则当TextBox
失去焦点时,TextBox
中通常会出现红色边框,表示错误。但是在包含IsFocused
作为其绑定源的TextBox
中,该值会变回先前的有效值(如果在输入3之前有39,则TextBox
会变回39)。
使用下面的代码,您可以重现该问题:
TestViewModel.cs
public class TestViewModel
{
public double? NullableValue { get; set; }
}
<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>
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;
}
}
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
的IsFocused
属性绑定到MultiBinding
中。当焦点改变时,这直接具有迫使更新绑定目标的效果。
在验证失败的情况下,会在很短的时间内触发验证规则,设置了错误,但是焦点实际上尚未更改。但这一切发生得太快,以至于用户看不到。而且由于验证失败,因此绑定源不会更新。
因此,当IsFocused
属性值更改时,在对输入值进行验证和拒绝后,接下来要发生的事情是重新评估绑定(因为源属性之一已更改!)以更新目标。并且由于实际源值从未更改,因此目标(TextBox
)将从您键入的内容恢复为源中存储的内容。
您应该如何解决?这取决于所需的确切行为。您有三个基本选项:
继续绑定到IsFocused
,然后添加UpdateSourceTrigger="PropertyChanged"
。这将保持基本的当前行为,即失去焦点时将旧值复制回去,但至少会在编辑值时为用户提供立即的验证反馈。
完全删除与IsFocused
的绑定。这样,绑定的目标将不再依赖于此,并且在焦点更改时也不会重新评估。问题解决了。 :)
继续绑定到IsFocused
,并添加逻辑,以便与验证进行交互不会导致将过时的值复制回TextBox
。
根据我们的来回评论,似乎上面的第三个选项是您的方案的首选,因为您希望在控件具有焦点时与没有控件时不同地设置值的文本表示形式。
我对用户界面的智慧表示怀疑,该界面根据控件是否聚焦而不同地格式化数据。当然,对焦点进行更改以影响整个视觉呈现是完全有意义的,但这通常涉及诸如下划线,突出显示等内容。根据控件是否聚焦而显示完全不同的字符串似乎可能会干扰用户的理解和理解。可能还会惹恼他们。
但是,我同意这是一个主观要点,并且显然,在您的情况下,您具有此特定行为,这对于您的规范而言是理想的,需要得到支持。因此,考虑到这一点,让我们看一下如何实现这种行为……
如果您希望能够绑定到IsFocused
属性,但是如果尚未真正更新源(即,如果验证错误阻止了该更改的发生),则无需进行更改以将焦点复制到控件的当前内容上,那么您还可以绑定到Validation.HasError
属性,并使用该属性控制转换器的行为。例如:
class TestMultiBindingConverter : IMultiValueConverter
{
private bool _hadError;
public object Convert(object[] values,
Type targetType, object parameter, CultureInfo culture)
{
bool? isFocused = values[1] as bool?,
hasError = values[2] as bool?;
if ((hasError == true) || _hadError)
{
_hadError = true;
return Binding.DoNothing;
}
if (values[0] != null)
{
return values[0].ToString() + (isFocused == true ? "" : " (+)");
}
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 };
_hadError = false;
return values;
}
}
object[] values2 = { DependencyProperty.UnsetValue };
return values2;
}
}
_hadError
来“记住”控件最近发生的情况。如果在验证检测到错误时调用该转换器,则该转换器将返回
Binding.DoNothing
(其效果暗示其名称为:)),并设置该标志。此后,无论发生什么情况,只要设置了该标志,转换器将始终不执行任何操作。
ConvertBack()
方法来更新源,并且这样做可以清除
_hadError
标志。这样可以确保控件内容永远不会由于绑定更新而被覆盖,除非自上次更新源以来没有错误。
<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="Nulleable: "/>
<TextBox x:Name="textBoxWrapper" Grid.Column="1" VerticalAlignment="Top">
<TextBox.Text>
<MultiBinding x:Name="TextBoxBinding" Mode="TwoWay"
UpdateSourceTrigger="PropertyChanged">
<Binding Path="NulleableValue"/>
<Binding Path="IsFocused"
RelativeSource="{RelativeSource Self}"
Mode="OneWay"/>
<Binding Path="(Validation.HasError)"
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>
_hadError
字段用于转换器本身。为了使以上内容正常工作,您需要为转换器所应用的每个绑定单独设置转换器的实例。有其他方法可以唯一地跟踪每个控件的此类标志,但我认为对此方面的选项进行的扩展讨论不在此问题的范围内。如果您无法自行解决问题,请自行探索,并发布有关该方面的新问题。
关于c# - 为什么将TextBox的Value重置为先前的值而不显示错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34204136/
我正在尝试使用谷歌浏览器的 Trace Event Profiling Tool分析我正在运行的 Node.js 应用程序。选择点样本后,我可以在三种 View 之间进行选择: 自上而下(树) 自上而
对于一个可能是菜鸟的问题,我们深表歉意,但尽管在 SO 上研究了大量教程和其他问题,但仍找不到答案。 我想做的很简单:显示一个包含大量数据库存储字符串的 Android ListView。我所说的“很
我已经开始了一个新元素的工作,并决定给 Foundation 5 一个 bash,看看它是什么样的。在创建带有水平字段的表单时,我在文档中注意到的第一件事是它们使用大量 div 来设置样式。所以我在下
我有一个 Windows 窗体用户控件,其中包含一个使用 BeginInvoke 委托(delegate)调用从单独线程更新的第 3 方图像显示控件。 在繁重的 CPU 负载下,UI 会锁定。当我附加
我有一堆严重依赖dom元素的JS代码。我目前使用的测试解决方案依赖于 Selenium ,但 AFAIK 无法正确评估 js 错误(addScript 错误不会导致您的测试失败,而 getEval 会
我正在制作一款基于滚动 2D map /图 block 的游戏。每个图 block (存储为图 block [21][11] - 每个 map 总共 231 个图 block )最多可以包含 21 个
考虑到以下情况,我是前端初学者: 某个 HTML 页面应该包含一个沉重的图像(例如 - 动画 gif),但我不想强制客户缓慢地等待它完全下载才能享受一个漂亮的页面,而是我更愿意给他看一个轻量级图像(例
我正在设计一个小软件,其中包括: 在互联网上获取资源, 一些用户交互(资源的快速编辑), 一些处理。 我想使用许多资源(它们都列在列表中)来这样做。每个都独立于其他。由于编辑部分很累,我想让用户(可能
我想比较两个理论场景。为了问题的目的,我简化了案例。但基本上它是您典型的生产者消费者场景。 (我关注的是消费者)。 我有一个很大的Queue dataQueue我必须将其传输给多个客户端。 那么让我们
我有一个二元分类问题,标签 0 和 1(少数)存在巨大不平衡。由于测试集带有标签 1 的行太少,因此我将训练测试设置为至少 70-30 或 60-40,因此仍然有重要的观察结果。由于我没有过多地衡量准
我是一名优秀的程序员,十分优秀!