已启动验证,但Silverlight 4中的用户控件未显示红色边框

时间:2012-02-29 11:14:23

标签: validation data-binding mvvm silverlight-4.0 user-controls

我创建了包含TextBox和PasswordBox的自定义用户控件。我还将TextBox绑定到UserName和PassowrdBox。 UserName在我的LoginViewModel类中使用[Required]属性定义。现在我的光标从TextBox离开而没有输入任何值,然后UserName属性fire 属性更改通知(INotifyPropertyChanged), 但不能用红色边框标记我的文本框(位于用户控件内)。

以下是我的用户控件的代码。

RestrictedBox.xaml

<Grid x:Name="LayoutRoot" Background="Transparent" Margin="0" >
        <TextBox x:Name="txtTextBox" HorizontalAlignment="Stretch" Height="25" />
        <PasswordBox x:Name="txtPasswordBox" HorizontalAlignment="Stretch" Height="25" />
</Grid>

RestrictedBox.xaml.cs

public partial class RestrictedBox : UserControl
    {
        #region Properties
        public string Value
        {
            get { return (string)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(RestrictedBox), new PropertyMetadata("", ValueChanged));
        private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }
        public bool Updateable
        {
            get { return (bool)GetValue(UpdateableProperty); }
            set { SetValue(UpdateableProperty, value); }
        }
        public static readonly DependencyProperty UpdateableProperty = DependencyProperty.Register("Updateable", typeof(bool), typeof(RestrictedBox), new PropertyMetadata(UpdateableChanged));
        private static void UpdateableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }
        public bool Redactable
        {
            get { return (bool)GetValue(RedactableProperty); }
            set { SetValue(RedactableProperty, value); }
        }
        public static readonly DependencyProperty RedactableProperty = DependencyProperty.Register("Redactable", typeof(bool), typeof(RestrictedBox), new PropertyMetadata(RedactableChanged));
        private static void RedactableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }
        #endregion
        #region Constructors
        public RestrictedBox()
        {
            InitializeComponent();
            txtTextBox.SetBinding(TextBox.TextProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay});
            txtTextBox.SetBinding(TextBox.VisibilityProperty, new Binding("Redactable") { Source = this, Converter = new BoolToVisibilityConverterReverse() });
            txtPasswordBox.SetBinding(PasswordBox.PasswordProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay });
            txtPasswordBox.SetBinding(TextBox.VisibilityProperty, new Binding("Redactable") { Source = this, Converter = new BoolToVisibilityConverter() });
       }
        #endregion
    }

以下是我使用自定义用户控件的代码

LoginView.xaml

<Control:RestrictedBox x:Name="UserName" VerticalAlignment="Top" TabIndex="2" Grid.Row="1"  Grid.Column="1" HorizontalAlignment="Stretch" Height="40" Value="{Binding Path=LoginModelValue.UserName, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, ValidatesOnExceptions=True,
 ValidatesOnDataErrors=True, NotifyOnValidationError=True}" Validatevalue:UpdateSourceTriggerHelper.UpdateSourceTrigger="True" Redactable="True" Updateable="True"  />

LoginView.xaml.cs

[Export(typeof(LoginView))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public partial class LoginView : UserControl, IPageTitle
    {
        #region Constuctors
        public LoginView()
        {
            InitializeComponent();
        }
        [Import]
        public LoginViewModel ViewModel
        {
            get {return this.DataContext as LoginViewModel;}            
            set { DataContext = value; }
        }
        #endregion
    }

LoginViewModel.cs

 [Export]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class LoginViewModel : INotifyPropertyChanged, IRegionMemberLifetime
    {
        private LoginModel _LoginModelValue;
        public LoginModel LoginModelValue
        {
            get { return _LoginModelValue; }
            set
            {
                _LoginModelValue = value;
                OnPropertyChanged("LoginModelValue");
            }
        }
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        void LoginModelValue_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (LoginModelValue.IsValidObject())
            {
                LoginCommand.RaiseCanExecuteChanged();
                IsEnabled = LoginModelValue.IsValidObject();
                SetIncorrectLogin(!IsEnabled);
            }
        }
        #endregion
    }

有人知道我为什么没有使用自定义用户控件中的TextBox包围Red Border吗?

任何帮助,建议和意见都将受到高度赞赏!

谢谢,

Imdadhusen

2 个答案:

答案 0 :(得分:1)

正如我已经说过的,验证仅适用于一个绑定,并且不会像您的情况那样由后续绑定继承。

最简单的方法是将Required注释直接添加到控件的Value属性中,然后再次验证它:

[Required]
public string Value
{
    get { return (string)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(RestrictedBox), new PropertyMetadata("", ValueChanged));
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var rb = d as RestrictedBox;
    Validator.ValidateProperty(rb.Value, new ValidationContext(rb, null, null) { MemberName = "Value" });
}

并将ValidatesOnExceptions属性添加到绑定中,以便验证起作用:

txtTextBox.SetBinding(TextBox.TextProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay, 
    ValidatesOnExceptions = true });
//...
txtPasswordBox.SetBinding(PasswordBox.PasswordProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay, 
    ValidatesOnExceptions = true });
//...

另一种方法:删除所有属性并将RestrictedBox控件直接绑定到视图模型。

<TextBox x:Name="txtTextBox" HorizontalAlignment="Stretch" Height="25" 
        Text="{Binding LoginModelValue.UserName, Mode=TwoWay, ValidatesOnExceptions=True}" />
<PasswordBox x:Name="txtPasswordBox" HorizontalAlignment="Stretch" Height="25" 
            Password="{Binding LoginModelValue.UserName, Mode=TwoWay, ValidatesOnExceptions=True}" />

这些解决方案似乎远非理想,但实际上数据注释的验证在设计上并不好。我建议使用INotifyDataErrorInfo界面。

答案 1 :(得分:1)

现在我使用以下代码解决了问题。我已经更换了以下行

txtTextBox.SetBinding(TextBox.VisibilityProperty, new Binding("Redactable") { Source = this, Converter = new BoolToVisibilityConverterReverse() });

 this.MapBinding(RestrictedControl.ValueProperty, txtTextBox, TextBox.TextProperty);

并添加以下代码。就是这样。

namespace QSys.Library.Helpers
{
    public static class FrameworkElementExtension
    {
        public static void MapBinding(this FrameworkElement element, DependencyProperty firstProperty, FrameworkElement targetElement, DependencyProperty secondProperty)
        {
            BindingExpression firstExpression = element.GetBindingExpression(firstProperty);
            if (firstExpression != null && firstExpression.ParentBinding != null)
            {
                targetElement.SetBinding(secondProperty, firstExpression.ParentBinding);
            }
        }
    }
}

我特别感谢大家如何寻找这个。而且我也非常感谢Rakesh Gunijan(http://www.codeproject.com/Articles/293302/Silverlight-user-control-validation)如何非常清楚地表达。

谢谢,

Imdadhusen