WPF验证未在文本框的第一个失去焦点时触发

WPF验证未在文本框的第一个失去焦点时触发,wpf,validation,focus,Wpf,Validation,Focus,我正在尝试针对一个对象验证WPF表单。当我在文本框中键入内容失去焦点,返回文本框,然后删除我所写的内容时,将触发验证。但是,如果我只是加载WPF应用程序并在文本框中添加tab,而没有写入和删除文本框中的任何内容,那么它就不会被触发 下面是Customer.cs类: public class Customer : IDataErrorInfo { public string FirstName { get; set; } public string Last

我正在尝试针对一个对象验证WPF表单。当我在文本框中键入内容失去焦点,返回文本框,然后删除我所写的内容时,将触发验证。但是,如果我只是加载WPF应用程序并在文本框中添加tab,而没有写入和删除文本框中的任何内容,那么它就不会被触发

下面是Customer.cs类:

public class Customer : IDataErrorInfo
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public string Error
        {
            get { throw new NotImplementedException(); }
        }
        public string this[string columnName]
        {
            get
            {
                string result = null;

                if (columnName.Equals("FirstName"))
                {
                    if (String.IsNullOrEmpty(FirstName))
                    {
                        result = "FirstName cannot be null or empty"; 
                    }
                }
                else if (columnName.Equals("LastName"))
                {
                    if (String.IsNullOrEmpty(LastName))
                    {
                        result = "LastName cannot be null or empty"; 
                    }
                }
                return result;
            }
        }
    }
以下是WPF代码:

<TextBlock Grid.Row="1" Margin="10" Grid.Column="0">LastName</TextBlock>
<TextBox Style="{StaticResource textBoxStyle}" Name="txtLastName" Margin="10"
         VerticalAlignment="Top" Grid.Row="1" Grid.Column="1">
    <Binding Source="{StaticResource CustomerKey}" Path="LastName"
             ValidatesOnExceptions="True" ValidatesOnDataErrors="True"
             UpdateSourceTrigger="LostFocus"/>         
</TextBox>
LastName

不幸的是,这是出于设计。WPF验证仅在控件中的值已更改时激发

难以置信,但这是真的。到目前为止,WPF验证是众所周知的一大难题——这太可怕了


但是,您可以做的一件事是从控件的属性获取绑定表达式并手动调用验证。这很糟糕,但很有效

我也遇到了同样的问题,并找到了一种非常简单的解决方法:在窗口的已加载事件中,只需将txtLastName.Text=String.Empty放入。就这样!!由于对象的属性已更改(已设置为空字符串),因此将触发验证

看看ValidationRule的属性。它将在首次加载数据时进行验证。如果您试图捕获空字段或空字段,这是很好的

您将更新绑定元素,如下所示:

<Binding 
    Source="{StaticResource CustomerKey}" 
    Path="LastName" 
    ValidatesOnExceptions="True" 
    ValidatesOnDataErrors="True" 
    UpdateSourceTrigger="LostFocus">
    <Binding.ValidationRules>
        <DataErrorValidationRule
            ValidatesOnTargetUpdated="True" />
    </Binding.ValidationRules>
</Binding>

如果您不反对在代码中添加一点逻辑,您可以使用以下方法处理实际的LostFocus事件:

<Binding 
    Source="{StaticResource CustomerKey}" 
    Path="LastName" 
    ValidatesOnExceptions="True" 
    ValidatesOnDataErrors="True" 
    UpdateSourceTrigger="LostFocus">
    <Binding.ValidationRules>
        <DataErrorValidationRule
            ValidatesOnTargetUpdated="True" />
    </Binding.ValidationRules>
</Binding>
.xaml

<TextBox LostFocus="TextBox_LostFocus" ....

下面的代码在所有控件上循环并验证它们。不一定是首选方式,但似乎有效。它只做文本块和文本框,但你可以很容易地改变它

public static class PreValidation
{

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }


    public static void Validate(DependencyObject depObj)
    {
        foreach(var c in FindVisualChildren<FrameworkElement>(depObj))
        {
            DependencyProperty p = null;

            if (c is TextBlock)
                p = TextBlock.TextProperty;
            else if (c is TextBox)
                p = TextBox.TextProperty;

            if (p != null && c.GetBindingExpression(p) != null) c.GetBindingExpression(p).UpdateSource();
        }

    }
}
公共静态类预验证
{
公共静态IEnumerable FindVisualChildren(DependencyObject depObj),其中T:DependencyObject
{
if(depObj!=null)
{
for(int i=0;i

只要在窗口或控件上调用Validate,它就会为您预先验证它们。

我发现处理此问题的最佳方法是在文本框的LostFocus事件上执行类似操作

    private void dbaseNameTextBox_LostFocus(object sender, RoutedEventArgs e)
    {
        if (string.IsNullOrWhiteSpace(dbaseNameTextBox.Text))
        {
            dbaseNameTextBox.Text = string.Empty;
        }
    }

然后它会看到一个错误

谢谢,但该解决方案不可扩展,很难在所有页面上维护!如果使用reflector进行检查,您将看到DataErrorValidationRule已将“ValidateOnTargetUpdated”属性设置为true。它使用指定此参数的参数调用继承的构造函数。因此,如图所示添加属性指定不会产生任何影响。好主意-我一直在尝试解决一个类似的问题,这看起来很有希望。这对我来说是一个自定义规则!谢谢你,老兄!这是一个答案,还是你在试图寻求帮助解决你遇到的问题?不幸的是,这可以应用于MVVM逻辑。当您不想修改隐藏的代码时,有没有关于如何执行此操作的提示?我认为视图中的代码“专为视图”在MVVM中与viewmodel没有关系是可以的。