Как добиться условной проверки с помощью IDataErrorInfo

У нас есть страница настроек конфигурации в моем приложении MVVM. Одно из полей (свойство: BackupFolderPath) здесь имеет элемент управления TextBox. Мы выполнили проверку этого элемента управления с помощью IDataErrorInfo. Валидация в основном проверяет существование этого пути.

Какие валидации были реализованы:

  1. При запуске приложения проверяется наличие BackupFolderPath. Если этот путь не существует, приложение перейдет на страницу настроек и пометит границу элемента управления красным цветом.

  2. Если пользователь находится на странице настроек и BackupFolderPath существует. Теперь, если мы попытаемся изменить BackupFolderPath, проверка снова вступит в силу и цвет границы элемента управления станет красным.

Что мы хотим изменить сейчас:

  1. Мы хотим сохранить красный цвет границы только при запуске приложения, если путь не существует. Во втором случае, если путь существует, но пользователь пытается изменить его из пользовательского интерфейса, мы не хотим вызывать проверку, которая означает, что цвет границы текстового поля не должен меняться на красный. Мы хотим, чтобы пользователь мог изменить путь здесь.

Фрагмент кода XAML:

<UserControl.Resources>
 <!--—Error Template to change the default behaviour-->
        <ControlTemplate x:Key="ErrorTemplate">
            <DockPanel LastChildFill="True">
                <Border BorderBrush="Red" BorderThickness="1">
                    <AdornedElementPlaceholder />
                </Border>
            </DockPanel>
        </ControlTemplate>
        <!-- —To display tooltip with the error-->
        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
</UserControl.Resources>

<TextBox x:Name="txtBackupFilePath" Text="{Binding Path=BackupFolderPath,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,NotifyOnValidationError=True}"  Validation.ErrorTemplate="{StaticResource ErrorTemplate}"   Grid.Column="1" Grid.Row="4" Margin="0,0,155,0" Height="30" Width="500" TextWrapping="NoWrap" MaxLength="75" HorizontalAlignment="Left"/>

Фрагмент кода ViewModel:

 #region IDataErrorInfo Implementation

        public new string Error
        {
            get { return null; }
        }

        public new string this[string columnName]
        {
            get
            {
                string result = null;
                switch (columnName)
                {                        
                    case "BackupFolderPath":
                       if (!Directory.Exists(BackupFolderPath))
                            result = "Configuration settings path: \'" + BackupFolderPath+ "\' not available !";
                        break;
                    default:
                        break;
                }

                return result;
            }
        }

        #endregion

private string _backupFolderPath = string.Empty;
        public string BackupFolderPath
        {
            get { return _backupFolderPath ; }
            set
            {
                if (_backupFolderPath == value) return;

                _backupFolderPath = value; 
                NotifyOfPropertyChange(() => BackupFolderPath);
            }
        }

person WpfBee    schedule 27.03.2018    source источник
comment
Итак, если пользователь вводит недопустимый каталог, граница не должна стать красной, верно? Как вы изначально устанавливаете BackupFolderPath?   -  person mm8    schedule 27.03.2018
comment
Да, цель состоит в том, чтобы позволить пользователю иметь новый каталог, который мы создадим с помощью кнопки «Сохранить» на странице настроек (я не показывал его выше, чтобы упростить его). Первоначально (первый запуск приложения) мы предоставляем некоторые по умолчанию BackupFolderPath.   -  person WpfBee    schedule 27.03.2018
comment
И как именно вы предоставляете это значение?   -  person mm8    schedule 27.03.2018
comment
Простое решение — просто проверить, не пуст ли путь резервного копирования, и если да, установить для него значение Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), MyCompanyName, MyApplicationName) и покончить с этим.   -  person    schedule 27.03.2018
comment
@mm8: изначально это свойство остается пустым. Мы просим пользователя указать путь и сохранить его в файле конфигурации.   -  person WpfBee    schedule 27.03.2018
comment
Но значение должно быть где-то считано из конфига.   -  person mm8    schedule 27.03.2018
comment
@mm8: Да, мы записываем путь в файл конфигурации во время операции сохранения и проверяем физическое существование пути во время запуска приложения (используя файл конфигурации).   -  person WpfBee    schedule 27.03.2018


Ответы (1)


Сначала я был сбит с толку, почему вы вообще получаете какую-либо ошибку, когда они редактируют путь. Затем я заметил триггер updatesource привязки. У вас есть

UpdateSourceTrigger=PropertyChanged

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

Возможно, вам следует рассмотреть средство выбора файлов, а не текстовое поле.

person Andy    schedule 27.03.2018
comment
Вы правы насчет UpdateSourceTrigger. Вместо использования PropertyChanged я попробовал Default. Он не показывает красную границу во время изменения пути в элементе управления Textbox. Но проблема с этим подходом заключается в том, что во время запуска приложения, если кто-то удалит физический путь, он снова не окрасит границу в красный цвет, и это неправильно. Нам нужна красная рамка при запуске приложения, если путь физически не существует. - person WpfBee; 27.03.2018
comment
Я не знаю, как вы изначально создаете экземпляр своей модели представления, но сделайте это, представьте ее в представлении, а затем вызовите изменение свойства в поле. Возможно, вам потребуется сделать ваш метод raisepropertychanged общедоступным или что-то в этом роде. - person Andy; 27.03.2018