本文介绍了Silverlight IDataErrorInfo 消息未显示在自定义控件的文本框中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I created a custom password box user control which is able to show and hide the password. It just swaps out the standard password box with a textbox which is bound to the same password string property. It all works fine but now my data validation errors are no more shown, although they are being generated correctly in the background. Here's the xaml from my user control:

<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>

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

Here's how I use it in a view:

 <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>

在父视图的视图模型中,我们像这样实现了 IDataErrorInfo:

in the Parent view's viewmodel we implemented IDataErrorInfo like this:

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;
        }
    }

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

Now when I enter text in the custom password box, the validation logic is called just fine but it's not displayed. Do I have to adjust my user control for this?

这是我的密码框背后的代码:

Here's the code behind of my passwordbox:

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));
        }
    }


}

第二次如果有人向我解释在父窗口/控件的 xaml 中用户控件的绑定属性的基础知识,这也会有所帮助.我不太明白为什么用户控件没有获取相应父视图视图模型属性的属性更改事件,因为它是通过 xaml 绑定到这些事件的.

2nd It would also help if someone would just explain to me the basics of binding properties of usercontrols in the xaml of a parent window/control. I dont quite understand why the usercontrol doesnt get the property changed events of the corresponding parent views viewmodel properties since it is bound to those via xaml.

推荐答案

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

Here's my solution at last. Since I realized that the DataContext of the user control automatically is the ViewModel of the parent view, I dumped the binding of the Password dependency property completely. I introduced a new parameter in the control which has to be set to the password property of the parent view model. I then use this string to do a manual binding of the textbox and the password box in the loaded event of the control. Here's my code:

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.

Here's the XAML of the control.

<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>

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

Now you got a nice password visibility switcher control :)Comments appreciated!

这篇关于Silverlight IDataErrorInfo 消息未显示在自定义控件的文本框中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-28 00:32