Подтвердить что ты не робот

WPF-проверка не запускает первый LostFocus из TextBox

Я пытаюсь проверить форму WPF на объект. Проверка срабатывает, когда я печатаю что-то в текстовом поле, теряют фокус, возвращаются в текстовое поле, а затем стирают все, что я написал. Но если я просто загружаю приложение WPF и удаляю текстовое поле без записи и стирания чего-либо из текстового поля, он не запускается.

Вот класс 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>
4b9b3361

Ответ 1

Если вы не против того, чтобы поместить немного логики в свой код позади, вы можете обработать событие LostFocus с чем-то вроде этого:

.xaml

<TextBox LostFocus="TextBox_LostFocus" ....

.xaml.cs

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
     ((Control)sender).GetBindingExpression(TextBox.TextProperty).UpdateSource();
}

Ответ 2

К сожалению, это по дизайну. Проверка WPF срабатывает только при изменении значения в элементе управления.

Невероятно, но верно. До сих пор валидация WPF - это большая пресловутая боль - это ужасно.

Однако одна из вещей, которую вы можете сделать, - получить выражение привязки из свойства control и вручную вызвать проверки. Это отстой, но он работает.

Ответ 3

Посмотрите на свойство ValidatesOnTargetUpdated свойства ValidationRule. Он будет проверять, когда данные будут сначала загружены. Это хорошо, если вы пытаетесь поймать пустые или нулевые поля.

Вы обновили бы свой связующий элемент следующим образом:

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

Ответ 4

Я столкнулся с той же проблемой и нашел очень простой способ решить эту проблему: в событии Loaded вашего окна просто поместите txtLastName.Text = String.Empty. Это!! Поскольку свойство вашего объекта изменилось (было установлено на пустую строку), запуск проверки!

Ответ 5

Следующий код перебирает все элементы управления и проверяет их. Не обязательно предпочтительный способ, но, похоже, работает. Это только TextBlocks и TextBoxes, но вы можете легко изменить его.

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();
        }

    }
}

Просто вызовите "Проверить" в своем окне или управлении, и он должен предварительно проверить их для вас.

Ответ 6

Я узнал, что лучший способ справиться с этим - это событие LostFocus в текстовом поле. Я делаю что-то вроде этого

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

Затем он видит ошибку