Silverlight IDataErrorInfo消息未显示在自定义控件的文本框中

时间:2011-03-03 16:03:09

标签: silverlight validation user-controls

我创建了一个自定义密码框用户控件,可以显示和隐藏密码。它只是将标准密码框与一个绑定到相同密码字符串属性的文本框交换出来。一切正常,但现在我的数据验证错误不再显示,尽管它们是在后台正确生成的。这是来自我的用户控件的xaml:

<UserControl x:Class="Controls.EAPPasswordBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" x:Name="_root">

<Grid x:Name="LayoutRoot" Background="White">
    <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Top">
        <PasswordBox x:Name="pwdBox" Password="{Binding Password, Mode=TwoWay,ValidatesOnDataErrors=True}" />
        <TextBox x:Name="txtBox" Text="{Binding Password, Mode=TwoWay,ValidatesOnDataErrors=True}" />
    </StackPanel>
</Grid>

以下是我在视图中使用它的方式:

 <local:EAPPasswordBox x:Name="pwdBox"
                Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="2"  Password="{Binding password,Mode=TwoWay, ValidatesOnDataErrors=True}"  ShowText="{Binding showPassword,Mode=TwoWay}"></local:EAPPasswordBox>

在Parent视图的viewmodel中我们实现了IDataErrorInfo,如下所示:

public string this[string columnName]
    {
        get
        {
            string Result = "";
            switch(columnName.ToLower())
            {
                case "password":
                    {
                        Result = Validatepassword();
                        break;
                    }
                case "password2":
                    {
                        Result = Validatepassword2();
                        break;
                    }
                default:
                    {
                        Result = this.ValidateStringValue(columnName);

                        break;
                    }
            }
            return Result;
        }
    }

现在,当我在自定义密码框中输入文本时,调用验证逻辑就好了,但是没有显示。我是否必须为此调整用户控件?

编辑:这是我的密码箱背后的代码:

public partial class EAPPasswordBox : UserControl, INotifyPropertyChanged
{
    public bool ShowText
    {

        get { return (bool)GetValue(ShowTextProperty); }
        set { 

            SetValue(ShowTextProperty, value);
               if (value == true)
               {
                   this.pwdBox.Visibility = System.Windows.Visibility.Collapsed;
                   this.txtBox.Visibility = System.Windows.Visibility.Visible;
               }
               else
               {
                   this.pwdBox.Visibility = System.Windows.Visibility.Visible;
                   this.txtBox.Visibility = System.Windows.Visibility.Collapsed;
               }
        }

    }

    public string Password
    {
        get { return (string)GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }

    private Visibility _PwdBoxVisibility;

    public Visibility PwdBoxVisibility
    {
        get { return _PwdBoxVisibility; }
        set
        {
            _PwdBoxVisibility = value; NotifyPropertyChanged("PwdBoxVisibility");
        }
    }

    private Visibility _TxtBoxVisibility;

    public Visibility TxtBoxVisibility
    {
        get { return _TxtBoxVisibility; }
        set
        {
            _TxtBoxVisibility = value; NotifyPropertyChanged("TxtBoxVisibility");
        }
    }

    public static readonly DependencyProperty PasswordProperty =
         DependencyProperty.Register("Password", typeof(string), typeof(EAPPasswordBox), null);

    public static readonly DependencyProperty ShowTextProperty =
         DependencyProperty.Register("ShowText", typeof(bool), typeof(EAPPasswordBox), new PropertyMetadata(OnShowTextPropertyChanged));

    public EAPPasswordBox()
    {
        InitializeComponent();
        this.pwdBox.SetBinding(PasswordBox.PasswordProperty, new System.Windows.Data.Binding() { Source = this, Path = new PropertyPath("Password"), Mode = BindingMode.TwoWay,ValidatesOnDataErrors=true });
        this.txtBox.SetBinding(TextBox.TextProperty, new System.Windows.Data.Binding() { Source = this, Path = new PropertyPath("Password"), Mode = BindingMode.TwoWay, ValidatesOnDataErrors=true });

        this.ShowText = false;
    }


    private static void OnShowTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        EAPPasswordBox passwordBox = d as EAPPasswordBox;

        if (passwordBox != null)
        {
            passwordBox.ShowText=(bool)e.NewValue;
        }

    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }


}

2nd Edit:如果有人会向我解释在父窗口/控件的xaml中绑定usercontrols属性的基础知识,也会有所帮助。我不太明白为什么usercontrol不会获取相应父视图viewmodel属性的属性更改事件,因为它通过xaml绑定到那些。

1 个答案:

答案 0 :(得分:1)

这是我的解决方案。由于我意识到用户控件的DataContext自动是父视图的ViewModel,因此我完全转储了Password依赖属性的绑定。我在控件中引入了一个新参数,该参数必须设置为父视图模型的password属性。然后,我使用此字符串在控件的已加载事件中对文本框和密码框进行手动绑定。这是我的代码:

public partial class EAPPasswordBox : UserControl, INotifyPropertyChanged
{
    public bool ShowText
    {

        get { return (bool)GetValue(ShowTextProperty); }
        set { 

            SetValue(ShowTextProperty, value);
               if (value == true)
               {
                   this.pwdBox.Visibility = System.Windows.Visibility.Collapsed;
                   this.txtBox.Visibility = System.Windows.Visibility.Visible;
               }
               else
               {
                   this.pwdBox.Visibility = System.Windows.Visibility.Visible;
                   this.txtBox.Visibility = System.Windows.Visibility.Collapsed;
               }
        }

    }

    public string PasswordPropertyName { get; set; }



    private Visibility _PwdBoxVisibility;

    public Visibility PwdBoxVisibility
    {
        get { return _PwdBoxVisibility; }
        set
        {
            _PwdBoxVisibility = value; NotifyPropertyChanged("PwdBoxVisibility");
        }
    }

    private Visibility _TxtBoxVisibility;

    public Visibility TxtBoxVisibility
    {
        get { return _TxtBoxVisibility; }
        set
        {
            _TxtBoxVisibility = value; NotifyPropertyChanged("TxtBoxVisibility");
        }
    }


    public static readonly DependencyProperty ShowTextProperty =
         DependencyProperty.Register("ShowText", typeof(bool), typeof(EAPPasswordBox), new PropertyMetadata(OnShowTextPropertyChanged));

    public EAPPasswordBox()
    {
        InitializeComponent();
        this.ShowText = false;
    }


    private static void OnShowTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        EAPPasswordBox passwordBox = d as EAPPasswordBox;

        if (passwordBox != null)
        {
            passwordBox.ShowText=(bool)e.NewValue;
        }

    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    private void _root_Loaded(object sender, RoutedEventArgs e)
    {
        this.pwdBox.SetBinding(PasswordBox.PasswordProperty, new System.Windows.Data.Binding() { Source = this.DataContext, Path = new PropertyPath(PasswordPropertyName), Mode = BindingMode.TwoWay, ValidatesOnDataErrors = true });
        this.txtBox.SetBinding(TextBox.TextProperty, new System.Windows.Data.Binding() { Source = this.DataContext, Path = new PropertyPath(PasswordPropertyName), Mode = BindingMode.TwoWay, ValidatesOnDataErrors = true });

    }


}

这是控件的XAML。

<UserControl x:Class="GAB.EAP2011.Controls.EAPPasswordBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" x:Name="_root" Loaded="_root_Loaded">

<Grid x:Name="LayoutRoot" Background="White">
    <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Top">
        <PasswordBox x:Name="pwdBox"   />
        <TextBox x:Name="txtBox"   />
    </StackPanel>
</Grid>

以下是如何使用它:

<local:EAPPasswordBox x:Name="pwdBox"
                Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="2" PasswordPropertyName="password" ShowText="{Binding showPassword,Mode=TwoWay}"></local:EAPPasswordBox>

现在你有一个很好的密码可见性切换器控件:) 评论赞赏!