#c# #.net #wpf #validation
#c# #.net #wpf #проверка
Вопрос:
У меня есть 2 пароля. Мне нужно проверить, совпадают ли пароли. Я не хочу записывать это условие в код [].xaml.cs, но я хочу пометить поле пароля красным, когда пароли не совпадают.
Должен ли я написать специальное ValidationRule, какой-нибудь код в ViewModel или что-то еще? Кто-нибудь может мне помочь? Теперь проверка записывается в [].xaml.cs, но я хочу этого избежать.
Комментарии:
1. Что плохого в том, что проверка выполняется внутри xaml.cs?
2. Я хочу использовать более красивое решение этой проблемы. Я не могу перенести проверку внутри xaml.cs в другое представление без ее копирования.
Ответ №1:
Использование:
<PasswordBox Name="tbPassword" />
<PasswordBox Name="tbPasswordConf" />
<PasswordValidator
Box1="{Binding ElementName=tbPassword}"
Box2="{Binding ElementName=tbPasswordConf}" />
Код (этот код не охватывает все случаи):
public class PasswordValidator : FrameworkElement
{
static IDictionary<PasswordBox, Brush> _passwordBoxes = new Dictionary<PasswordBox, Brush>();
public static readonly DependencyProperty Box1Property = DependencyProperty.Register("Box1", typeof(PasswordBox), typeof(PasswordValidator), new PropertyMetadata(Box1Changed));
public static readonly DependencyProperty Box2Property = DependencyProperty.Register("Box2", typeof(PasswordBox), typeof(PasswordValidator), new PropertyMetadata(Box2Changed));
public PasswordBox Box1
{
get { return (PasswordBox)GetValue(Box1Property); }
set { SetValue(Box1Property, value); }
}
public PasswordBox Box2
{
get { return (PasswordBox)GetValue(Box2Property); }
set { SetValue(Box2Property, value); }
}
private static void Box1Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
private static void Box2Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var pv = (PasswordValidator)d;
_passwordBoxes[pv.Box2] = pv.Box2.BorderBrush;
pv.Box2.LostFocus = (obj, evt) =>
{
if (pv.Box1.Password != pv.Box2.Password)
{
pv.Box2.BorderBrush = new SolidColorBrush(Colors.Red);
}
else
{
pv.Box2.BorderBrush = _passwordBoxes[pv.Box2];
}
};
}
}
Кроме того, можно определить свойство dependency со стилем ошибки и установить его вместо BorderBrush. Но я не знаю, как использовать в этом случае стандартную ErrorTemplate.
Комментарии:
1. Вероятно, вам следует сделать это более идиоматичным, сделав это присоединенным свойством. Используется как:
<PasswordBox x:Name="tbPasswordConf" PasswordValidator.ValidateAgainst="{Binding ElementName=tbPassword}" ... />
.2. Это хорошее предложение. Я попробую. Спасибо. Знаете ли вы, как я могу использовать стандартную ErrorTemplate, которая использовалась в ValidationRules вместо настройки BorderBrush?
3. Fwiw: Я использовал это решение с добавлением
IsValid
свойства, чтобы я мог сообщить ViewModel о любых проблемах и остановить операцию сохранения.
Ответ №2:
Создайте свойство, доступное только для чтения, в вашей ViewModel и верните кисть для границы поля PasswordConfirmBox, а затем привяжите текстовое поле к этому свойству
РЕДАКТИРОВАТЬ после полученных комментариев Я не тестировал это, и могут быть незначительные ошибки, но таким образом вы можете возвращать другой тип в зависимости от параметра converterparameter
public bool PasswordValidation
{
get
{
if (textBox1.Text == textBox2.Text)
return true;
else
return
false;
}
}
Преобразователи значений:
public class ValConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter == "")
{
if ((value as bool?) ?? false)
return Visibility.Hidden;
else
return Visibility.Visible;
}
else if (parameter == "")
{
if ((value as bool?) ?? false)
return new SolidColorBrush(Colors.Black);
else
return new SolidColorBrush(Colors.Red);
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter == "Visibility")
{
if ((System.Windows.Visibility)value == Visibility.Visible)
return false;
else
return true;
}
else if (parameter == "Brush")
{
if (((SolidColorBrush)value).Color == Colors.Black)
return true;
else
return false;
}
}
Xaml:
<Window.Resources>
<vis:ValConverter x:Key="valConverter"/>
</Window.Resources>
<TextBox Name="textBox1"/>
<TextBox Name="textBox2" BorderBrush="{Binding ConfirmBorder,Converter={StaticResource valConverter},ConverterParameter=Brush}" />
<TextBlock Text="Passwords Does not Match!" BorderBrush="{Binding ConfirmBorder,Converter={StaticResource valConverter},ConverterParameter=Visibility}"/>
Комментарии:
1. В будущем я могу заменить его в специальной всплывающей подсказке сообщением, поэтому я не могу этого сделать.
2. Когда он заменяется всплывающей подсказкой, вы можете просто изменить его, чтобы возвращать логическое значение, указывающее видимость всплывающих подсказок вместо границы? Другой альтернативой является использование IValueConverter, который вернет true, когда кисть красная, и false, если кисть синяя, или альтернативно возвращает логическое значение и использует IValueConverter для преобразования кисти? Будет быстрее создать 2 отдельных свойства или просто изменить свойство, хотя
3. Я хочу использовать его как компонент. Просто привяжите компонент к двум паролям и все заработает. Ваше решение сложно расширить и повторно использовать. У меня есть 3 места, где это необходимо.
4. Совпадает ли это с тем, что у вас было до того, как вы задали вопрос, если да, то предоставление более подробной информации в вопросе сэкономило бы мне много времени
5. Извините, но мне нужно более гибкое решение.