我仍然在WPF中进行验证。
我有一个自定义验证规则,要求文本出现在文本框中,即它强制执行强制字段约束。
<TextBox local:Masking.Mask="^[a-zA-Z0-9]*$" x:Name="CameraIdCodeTextBox" Grid.Row="1" Grid.Column="1">
<Binding Path="CameraIdCode" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True" ValidatesOnExceptions="True">
<Binding.ValidationRules>
<localValidation:RequiredFieldRule />
</Binding.ValidationRules>
</Binding>
</TextBox>
问题是,当Window首次加载时,TextBox中没有文本(正如您所期望的那样)。但Text属性被绑定到ViewModel上的属性,因此,验证规则正在触发,表明Window存在问题 - 在用户甚至有机会违反业务规则之前。
这是一个以前解决过的问题吗?我无法成为第一个体验这一点的人。我确定这是年轻球员的陷阱。
答案 0 :(得分:0)
这有几种模式。我通常在类/模型上实现ISupportInitialize
接口,这将要求您在这些方法中创建BeginInit()
和EndInit()
我只需将私有bool _isInitializing
设置为true或false
在视图模型中或在何时/何时创建/填充模型/类使用begin和end init包装它:
var o = new SampleObject();
o.BeginInit()
o.StartDate = DateTime.Now; //just some sample property...
o.EndInit();
那么根据您的ValidationRule的调用方式,您可以检查_isInitializing
的状态,看看是否需要验证。
最近我一直在使用PropertyChanged
触发的属性验证器,所以你可以这样做:
[CustomValidator("ValidateStartDate")]
public DateTime StartDate
{ get ...
{
set
{
if(_startDate == value) return;
_startDate = value;
if(_isInitializing) return;
RaisePropertyChange(() => StartDate);
}..
如果您不想打扰ISupportInitialize
,请在构造期间传递属性中所需的所有值,而不是属性。绑定将首次查询属性上的getter并获取它们的值,之后将通过属性setter并获得验证:
//c-tor
public MyObject(DateTime start)
{
_startDate = start;
}
答案 1 :(得分:0)
已经有一段时间了,我应该更新这个问题。我使用Ian Griffths(O'Reilly的书)在WPF书中找到的课程来解决它:
public static class Validator
{
/// <summary>
/// This method forces WPF to validate the child controls of the control passed in as a parameter.
/// </summary>
/// <param name="parent">Type: DependencyObject. The control which is the descendent root control to validate.</param>
/// <returns>Type: bool. The validation result</returns>
public static bool IsValid(DependencyObject parent)
{
// Validate all the bindings on the parent
bool valid = true;
LocalValueEnumerator localValues = parent.GetLocalValueEnumerator();
while (localValues.MoveNext())
{
LocalValueEntry entry = localValues.Current;
if (BindingOperations.IsDataBound(parent, entry.Property))
{
Binding binding = BindingOperations.GetBinding(parent, entry.Property);
foreach (ValidationRule rule in binding.ValidationRules)
{
ValidationResult result = rule.Validate(parent.GetValue(entry.Property), null);
if (!result.IsValid)
{
BindingExpression expression = BindingOperations.GetBindingExpression(parent, entry.Property);
Validation.MarkInvalid(expression, new ValidationError(rule, expression, result.ErrorContent, null));
valid = false;
}
}
}
}
// Validate all the bindings on the children
for (int i = 0; i != VisualTreeHelper.GetChildrenCount(parent); ++i)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (!IsValid(child))
{
valid = false;
}
}
return valid;
}
}
然后,在视图中,我有以下配置:
<TextBox local:Masking.Mask="^[0-9]*$" IsEnabled="{Binding Path=LocationNumberEnabled}" Grid.Row="1" Grid.Column="3">
<Binding Path="LocationNumber" Mode="TwoWay" UpdateSourceTrigger="LostFocus" NotifyOnValidationError="True" ValidatesOnExceptions="True">
<Binding.ValidationRules>
<localValidation:PositiveNumberRule />
<localValidation:RequiredFieldRule />
</Binding.ValidationRules>
</Binding>
</TextBox>
像魅力一样工作!每当我想手动验证时,我就调用了IsValid方法。按下按钮。