c# - Passwordbox Validation.ErrorTemplate 未显示

标签 c# wpf

我正在尝试显示 PasswordBoxValidation.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);
                }
            }
        }
    }
}

我在基本 View 模型中实现了 INotifyDataError 接口(interface)。

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 上引发的托管发生验证错误的数据绑定(bind)属性。在你的情况下 <behavior:PasswordBoxBehaviorBinding SPassword="{Binding Path=Password, ValidatesOnNotifyDataErrors=True}" />意味着,您可以在行为中读取您的错误。

在这一点上,我也想反对你对 SPassword 的绑定(bind)所做的奇怪的黑客攻击。 .只需正常设置值即可:

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从附加行为到主机控件以一种优雅的方式。所以基本上,您的选择是以某种方式将行为中的错误链接绑定(bind)到密码框,或者创建一个额外的绑定(bind)到您的属性,因为此绑定(bind)将使用相同的验证机制并因此设置 Validation.ErrorsPasswordBox 上.我决定绑定(bind) View 模型 PasswordPasswordBox.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>

请注意,我从行为中的绑定(bind)中删除了绑定(bind)错误验证,因为它无论如何都没有用,我为 Tag 添加了绑定(bind)错误验证。绑定(bind)。

还有一件事:我改变了 SPassword默认情况下双向绑定(bind)的属性:

public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register(
    "SPassword",
    typeof(SecureString),
    typeof(PasswordBoxBehaviorBinding),
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

否则,请确保正确设置绑定(bind)模式。

关于c# - Passwordbox Validation.ErrorTemplate 未显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40135404/

相关文章:

c# - Access 数据库引擎的优点和缺点。 SQLite 之后的生活

c# - C# .NET 中的重载方法

c# - 打印位图文件

wpf - 如何设置文本 block 自动调整大小以适应 TreeView 的宽度?

c# - 数学题 : Determine the corner radius of an inner border based on outer corner radius/thickness

c# - 堆谜语中的对象

c# - 通过非制表符定界符的非结构化 XML?

c# - 在 NEST 中搜索没有类型特定类的特定查询(TermsQuery)

.net - 如何将样式应用于类及其后代?

C# WPF 显示来自 Mysql 的图像