Обработка ошибок в WPF PasswordBox - PullRequest
2 голосов
/ 20 января 2012

Я всегда восхищался тем, как Джош Смит создал свое пример приложения .И я также попытался эмулировать способ, которым ViewModels его приложения реализует свойство IDataErrorInfo и через пользовательский DataTemplate отображает ошибки перед пользователем.Вот шаблон данных, который он использует для отображения ошибки:

<DataTemplate DataType="{x:Type ValidationError}">
  <TextBlock FontSize="10"
             FontStyle="Italic"
             Foreground="Red"
             HorizontalAlignment="Right"
             Margin="0,1"
             Text="{Binding Path=ErrorContent}"/>
</DataTemplate>

Рабочий пример использования этого шаблона данных выглядит следующим образом:

<TextBox x:Name="txtUsername"
         Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"
         Width="300"
         Margin="2" 
         Text="{Binding Path=Username,
             ValidatesOnDataErrors=True,
             UpdateSourceTrigger=PropertyChanged}"
         Validation.ErrorTemplate="{x:Null}"/>

<ContentPresenter Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" 
                  Content="{Binding ElementName=txtUsername,
                      Path=(Validation.Errors).CurrentItem}"/>

Шаблон по умолчанию ErrorTemplate текстового поля(красная граница, которая появляется вокруг него) заменяется новым шаблоном ошибки, в котором ведущий содержимого, помещенный непосредственно под текстовым полем, сообщит пользователю об ошибке - безусловно, более совершенный и более элегантный шаблон.

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

К сожалению, формы входа требуют пароль (и впоследствии PasswordBox).PasswordBox не предоставляет «Пароль» как свойство зависимости.Я не хотел нарушать принцип MVVM, пытаясь избежать как можно большего количества кода, и поэтому мне хотелось пойти на упомянутый класс PasswordBoxAssistant здесь .В противном случае это хорошее решение, за исключением одной вещи.Это не позволяет мне проверить поле пароля с шаблоном данных Джоша.Я проверил свойство пароля моей ViewModel, чтобы оно не было пустым.Свойство проверяется, так как моя кнопка «Войти» не активируется без ввода пароля пользователем.Но сообщение «Введите пароль», которое я установил как часть проверки этого свойства, не обрабатывается предъявителем содержимого, который находится под паролем.Вот код:

<Label Content="Password:" Grid.Column="0" Grid.Row="2" Margin="2" />

<PasswordBox x:Name="PasswordBox"
             Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"
             Margin="2"
             Validation.ErrorTemplate="{x:Null}" 
             ff:PasswordBoxAssistant.BindPassword="true"  
             ff:PasswordBoxAssistant.BoundPassword="{Binding Path=Password,
                 Mode=TwoWay,
                 UpdateSourceTrigger=PropertyChanged}"/>

<ContentPresenter Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2"
                  Content="{Binding ElementName=PasswordBox,
                  Path=(Validation.Errors).CurrentItem}"/>

Нет необходимости говорить, что ff в приведенном выше коде обозначает ссылку на пространство имен:

xmlns:ff="clr-namespace:MyProject.UserViews"

Я уверен, что эта проблема возникает из-за паролясвойство было расширено классом помощника.Если я откажусь от этого подхода, мне придется удалить свойство Password из реализации IDataErrorInfo, и при щелчке по кнопке входа в систему его нужно будет подтвердить, предоставив пользователю окно сообщения.Но не без ущерба для согласованности.Я не очень осведомлен о свойствах зависимости;может ли быть какое-либо решение?Позволит ли изменение класса помощника каким-либо образом вернуть красное сообщение об ошибке на место?

Ответы [ 2 ]

4 голосов
/ 20 января 2012

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

Тем не менее, я думаю, что Password намеренно не является DependencyProperty, потому что вы действительно не должны хранить пароли в виде простого текста.

Обычно я в конечном итоге пропускаю PasswordBox.Password (илицелое PasswordBox) как CommandParameter для моего LoginCommand, тогда он может принимать данные и делать с ними все, что захочет.Обычно это означает хеширование чего-либо или что-то и сравнение его с хешем сохраненного пароля, чтобы увидеть, совпадает ли он.Если при входе в систему происходит сбой, я записываю соответствующее сообщение об ошибке в свойство моей ViewModel, которое привязано к интерфейсу входа в систему.

<Button Command="{Binding LoginCommand}" 
        CommandParameter="{Binding ElementName=MyPasswordBox, Path=Password}" />
0 голосов
/ 20 января 2012

Не уверен, что это ваша проблема, но вы не отключаете шаблон ErrorTemplate по умолчанию для PasswordBox.(т.е. нет Validation.ErrorTemplate="{x:Null})

РЕДАКТИРОВАТЬ: Можете ли вы использовать что-то вроде Wpf Inspector , чтобы проверить содержимое Validation.Errors PasswordBox, чтобы убедиться, что ошибка действительно существует (или даже просто привязать к нему ItemsControl)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...