在获得焦点时启动 WPF 验证

WPF validation launched on focus gained

我正在开发一个 IDataErrorInfo 来验证我的应用程序中的文本框。我有以下代码:

要验证的.cs class:

 public class UserInformation : IDataErrorInfo
{
    public string _name;
    public string _surname;

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    public string Surname
    {
        get { return _surname; }
        set { _surname = value; }
    }

    public override string  ToString()
    {
        return Name + " " + Surname;
    }

    public string this[string columnName]
    {
        get
        {
            if (columnName == null) return string.Empty;
            string result = string.Empty;
            if (columnName.Equals("Name"))
            {
                if (string.IsNullOrEmpty(_name))
                    result = "Name cannot be empty.";
            }
            return result;
        }
    }

    public string Error { get; private set; }
}

.xaml:

<TextBox Grid.Column="3" Grid.Row="0" Name="TextBoxName" 
        Style="{DynamicResource InnerTextBox}" 
        Validation.ErrorTemplate="{StaticResource ValidationErrorTemplate}">
        <TextBox.Text>
              <Binding Path="Name" Source="{StaticResource UserInformation}" 
                      ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged">
                 <Binding.ValidationRules>
                       <ExceptionValidationRule />
                  </Binding.ValidationRules>
                </Binding>
         </TextBox.Text>
      </TextBox>

ErrorTemplate:

<ControlTemplate x:Key="ValidationErrorTemplate">
    <DockPanel >
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
            <Grid Width="20" Height="20">
                <Ellipse Width="20" Height="20" Fill="Tomato" HorizontalAlignment="Center" VerticalAlignment="Center" />
                <TextBlock Foreground="White" FontWeight="Heavy" FontSize="8" HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center"
                   ToolTip="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">X</TextBlock>
            </Grid>
            <TextBlock Foreground="Tomato" FontWeight="12" Margin="2,0,0,0" FontSize="20"
                       Text="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
        </StackPanel>
        <AdornedElementPlaceholder x:Name="ErrorAdorner" />
    </DockPanel>
</ControlTemplate>

当我输入代码时代码工作正常。但是 当加载 TextBox 时,也会进行验证。而且我不希望它在获得焦点时发生,只有在它失去焦点或我更改文本(如此处发布的文本)时才发生。

如何避免在首次加载 TextBox 时考虑验证错误?

注意:即使我将 UpdateSourceTrigger 设置为 LostFocus,它仍在进行验证。

要实现您的目标,您需要:

首先,删除绑定上的 ValidatesOnDataErrors="True"。正如 docs 中所说:

Setting this property provides an alternative to using the DataErrorValidationRule element explicitly

我们将明确地使用它。然后使用 DataErrorValidationRule 而不是 ExceptionValidationRule 来正确处理 IDataErrorInfo 和数据错误。

最后,我们需要使用这条规则给我们的一些属性:

<Binding.ValidationRules>
    <DataErrorValidationRule ValidatesOnTargetUpdated="False" />
</Binding.ValidationRules>

ValidatesOnTargetUpdated on false will not trigger validation when target itself changes (i.e. on load). You can also play with ValidationStep 属性 用于额外控制。

编辑:
好的,我看到您需要在加载 时跳过验证,即使值未更改,您也需要在失去焦点时进行验证。好吧,验证规则不支持这一点,因为如果值没有更新,那么无论 UpdateSourceTrigger 设置如何,都不会调用更改事件并且不会发生验证。
简单的方法是通过向 TextBox 本身添加 LostFocus 处理程序来模拟此功能:

 private void ValidatedTextBox_LostFocus(object sender, RoutedEventArgs e)
 {
     var txt = (TextBox)sender;
     txt.GetBindingExpression(TextBox.TextProperty).UpdateSource();
 }

如果您需要对多个文本框执行此操作,您可以将代码移动到一些静态 class。
使用 Explicit update source trigger 可以获得相同的结果,它可以更清晰一些。

我没有任何 atm 示例,因为我搬到了你所拥有的。但是您需要创建一个 class,它将继承 system.windows.controls 中存在的 ValidationRule,然后覆盖 Validate 方法。

那么您的 xaml 文本框将看起来像这样

 <TextBox.Text>
<Binding Path="your binding here"    UpdateSourceTrigger="LostFocus" >
  <Binding.ValidationRules>
    <validationClass:yourRule/>  define this at the top of xaml page
  </Binding.ValidationRules>
</Binding>

你应该可以在 msdn 上找到示例,这里是关于验证规则的