Passwordbox验证.没有显示ErrorTemplate
本文关键字:显示 ErrorTemplate 验证 Passwordbox | 更新日期: 2023-09-27 18:13:42
我试图显示PasswordBox
中的Validation.ErrorTemplate
。然而,它并没有表现出来。在同一表单上,我有一个用户名TextBox
和ErrorTemplate
正确显示。
数据面板中PasswordBox的Xaml:
<PasswordBox Grid.Row="3" DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=ContentControl}}">
<PasswordBox.Style>
<Style>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right" Foreground="Red" FontSize="14" FontWeight="Bold">*</TextBlock>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</PasswordBox.Style>
<i:Interaction.Behaviors>
<behavior:PasswordBoxBehaviorBinding SPassword="{Binding Path=Password, ValidatesOnNotifyDataErrors=True}" />
</i:Interaction.Behaviors>
</PasswordBox>
下面是我正在使用的附加属性。
public class PasswordBoxBehaviorBinding : Behavior<PasswordBox>
{
public SecureString SPassword
{
get { return (SecureString)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
public static readonly DependencyProperty PasswordProperty
= DependencyProperty.Register(
"SPassword",
typeof(SecureString),
typeof(PasswordBoxBehaviorBinding),
new PropertyMetadata(null));
protected override void OnAttached()
{
AssociatedObject.PasswordChanged += AssociatedObject_PasswordChanged;
base.OnAttached();
}
protected override void OnDetaching()
{
AssociatedObject.PasswordChanged += AssociatedObject_PasswordChanged;
base.OnDetaching();
}
private void AssociatedObject_PasswordChanged(object sender, RoutedEventArgs e)
{
var binding = BindingOperations.GetBindingExpression(this, PasswordProperty);
if (binding != null)
{
if (binding.ResolvedSource != null)
{
PropertyInfo property = binding.ResolvedSource.GetType()
.GetProperty(binding.ParentBinding.Path.Path);
if (property != null)
{
property.SetValue(binding.ResolvedSource, AssociatedObject.SecurePassword);
}
}
}
}
}
我在基本视图模型中实现了INotifyDataError
接口。
public class ViewModelBase : BindableBase, INotifyDataErrorInfo
{
private IDictionary<string, List<string>> errors
= new Dictionary<string, List<string>>();
public bool HasErrors
{
get
{
return this.errors.Count > 0;
}
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
if ( this.errors.ContainsKey(propertyName) )
{
return this.errors[propertyName];
}
return null;
}
public void AddError(string propertyName, string error)
{
this.errors[propertyName] = new List<string> { error };
this.RaiseErrorsChanged(propertyName);
}
public void RemoveError(string propertyName)
{
if (this.errors.ContainsKey(propertyName))
{
this.errors.Remove(propertyName);
}
this.RaiseErrorsChanged(propertyName);
}
private void RaiseErrorsChanged(string propertyName)
{
if (this.ErrorsChanged != null)
{
this.ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
}
问题是,错误是在承载验证错误发生的数据绑定属性的DependencyObject
上引发的。在你的例子中,<behavior:PasswordBoxBehaviorBinding SPassword="{Binding Path=Password, ValidatesOnNotifyDataErrors=True}" />
意味着你可以在行为中读取你的错误。
SPassword
的绑定进行奇怪的修改。正常设置即可:
private void AssociatedObject_PasswordChanged(object sender, System.Windows.RoutedEventArgs e)
{
SPassword = AssociatedObject.SecurePassword;
// use debugger to verify, that the validation errors exist. Otherwise, no need for the following line of code
var behaviorErrors = Validation.GetErrors(this);
}
不幸的是,我还没有发现如何以一种优雅的方式将Validation.Errors
从附加行为提升到主机控件。因此,基本上,您的选择将以某种方式将错误从行为链绑定到密码盒,或者为您的属性创建一个额外的绑定,因为此绑定将使用相同的验证机制,从而将Validation.Errors
设置在PasswordBox
上。为了错误传播,我决定将视图模型Password
绑定到PasswordBox.Tag
。
<PasswordBox Width="200" Height="100" Tag="{Binding Password,ValidatesOnNotifyDataErrors=True,Mode=OneWay}">
<i:Interaction.Behaviors>
<behavior:PasswordBoxBehaviorBinding SPassword="{Binding Password}"/>
</i:Interaction.Behaviors>
</PasswordBox>
请注意,我从绑定行为中删除了绑定错误验证,因为它无论如何都没有用,并且我为Tag
绑定添加了绑定错误验证。
SPassword
属性,默认情况下是双向绑定:
public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register(
"SPassword",
typeof(SecureString),
typeof(PasswordBoxBehaviorBinding),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));