Wpf 第一次加载时的验证绑定

Wpf 第一次加载时的验证绑定,wpf,validation,binding,Wpf,Validation,Binding,我仍然在努力验证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" Not

我仍然在努力验证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>

问题是,当窗口第一次加载时,文本框中没有文本(正如您所期望的)。但是Text属性被绑定到ViewModel上的一个属性,因此,验证规则正在启动,这表明窗口存在问题——甚至在用户有机会违反业务规则之前


这是以前解决过的问题吗?我不可能是第一个体验到这一点的人。我相信这对年轻球员来说是个陷阱。

这有几种模式。我通常在类/模型上实现
ISupportInitialize
接口,这将要求您创建
BeginInit()
EndInit()
,在这些方法中,我只需将私有bool
设置为true或false

在视图模型中,或在何处/何时创建/填充模型/类,使用begin和end init将其包装:

var o = new SampleObject();
o.BeginInit()
o.StartDate = DateTime.Now; //just some sample property...
o.EndInit();
因此,根据ValidationRule的调用方式,您可以检查
\u初始化的状态,查看是否需要验证

最近我一直在使用属性验证器,该验证器在
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;
 }

已经有一段时间了,我应该更新这个问题。我用Ian Griffths(一本O'Reilly的书)在WPF书中找到的一个类解决了这个问题:

公共静态类验证程序
{
/// 
///此方法强制WPF验证作为参数传入的控件的子控件。
/// 
///类型:DependencyObject。要验证的子代根控件。
///类型:bool。验证结果
公共静态bool有效(DependencyObject父对象)
{
//验证父级上的所有绑定
bool valid=true;
LocalValueEnumerator localValues=parent.GetLocalValueEnumerator();
while(localValues.MoveNext())
{
LocalValueEntry=localValues.Current;
if(BindingOperations.IsDataBound(父项,entry.Property))
{
Binding Binding=BindingOperations.GetBinding(父项,entry.Property);
foreach(binding.ValidationRules中的ValidationRule规则)
{
ValidationResult=rule.Validate(parent.GetValue(entry.Property),null);
如果(!result.IsValid)
{
BindingExpression=BindingOperations.GetBindingExpression(父项,entry.Property);
Validation.MarkInvalid(表达式,新的ValidationError(规则,表达式,result.ErrorContent,null));
有效=错误;
}
}
}
}
//验证子节点上的所有绑定
for(int i=0;i!=VisualTreeHelper.GetChildrenCount(父项);+i)
{
DependencyObject子对象=VisualTreeHelper.GetChild(父对象,i);
如果(!IsValid(子项))
{
有效=错误;
}
}
返回有效;
}
}
然后,在视图上,我有以下配置:

<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方法。

你能试试。。。UpdateSourceTrigger=“LostFocus”您可以创建一个验证组,并且只能在用户第一次更改某个字段时启用它。@AngelWPF我已经尝试过了。当窗口加载时,它仍然在初始绑定上进行验证。@VladimirPerevalov是否可以启用和禁用绑定?如果是,我可能应该在第一次加载时禁用绑定。但我如何启用它?捕捉用户第一次变更的逻辑,与未来的每一次变更不同,应该是相当复杂的。我不知道为什么一个简单的RequiredField验证器如此困难;初始绑定时不会调用as集合。或者可能在验证中允许string.empty,但在集合中拒绝string.empty;(并抛出验证错误)。
<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>