Сосредоточьтесь на ошибке проверки с помощью WPF

#c# #wpf #data-binding #binding

#c# #wpf #привязка данных #привязка

Вопрос:

У меня есть небольшое приложение, в котором у меня есть текстовое поле, привязанное к модели через MVVM:

Моя модель:

 public class MyModel : INotifyPropertyChanged
{
    private double _myValue = 0;

    public event PropertyChangedEventHandler PropertyChanged;

    public double MyValue 
    {
        get => _myValue;
        set
        {
            if(value != _myValue)
            {
                if (value == 4)
                    throw new InvalidOperationException();
                _myValue = value;
                OnPropertyChanged();
            }
        }
    }

    /// <summary>
    /// Called when a property was changed.
    /// </summary>
    /// <param name="propertyName">Name of the affected property.</param>
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
  

Мой взгляд выглядит так:

 <Window x:Class="ValidationTests.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ValidationTests"
        mc:Ignorable="d"
        Title="MainWindow" Height="201.696" Width="322.679">
    
    <Window.Resources>
        <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" Text="{Binding MyValue, Mode=TwoWay, ValidatesOnExceptions=True}" 
                 HorizontalAlignment="Center" Width="150" VerticalAlignment="Center"/>
        <Button Grid.Row="1" HorizontalAlignment="Center" Width="100" VerticalAlignment="Center" Height="30" Content="Test"/>
    </Grid>
</Window>
  

Теперь я хочу сосредоточиться на текстовом поле при возникновении ошибки проверки. Как я могу этого добиться? Возможно ли это с помощью стиля?

введите описание изображения здесь

Комментарии:

1. Изучите реализацию IDataErrorInfo интерфейса для обработки этих вещей; зачем вводить InvalidOperationException неправильное значение, обрабатывайте их изящно.

2. Создание исключений в установщиках свойств по причинам проверки — это прекрасно

Ответ №1:

Если вы хотите предотвратить потерю фокуса клавиатуры до тех пор, пока TextBox не будет указано допустимое значение, вы можете обработать PreviewLostKeyboardFocus событие либо с помощью подключенного поведения, либо непосредственно в представлении:

 private void TextBox_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) =>
    e.Handled = Validation.GetHasError((TextBox)sender);
  

Вы также должны установить значение UpdateSourceTrigger PropertyChanged для выполнения проверки до того, как фокус будет потерян:

 <TextBox Text="{Binding MyValue, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}" 
         HorizontalAlignment="Center" Width="150" VerticalAlignment="Center"
         PreviewLostKeyboardFocus="TextBox_PreviewLostKeyboardFocus"/>
  

Вы не можете реализовать это в чистом XAML, используя a Style или что-то еще.