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

Validation 已启动验证,但Silverlight 4中的用户控件未显示红色边框,validation,data-binding,mvvm,silverlight-4.0,user-controls,Validation,Data Binding,Mvvm,Silverlight 4.0,User Controls,我创建了包含TextBox和PasswordBox的自定义用户控件。我还将TextBox绑定到用户名和PasswordBox。 用户名是在我的LoginViewModel类中用[Required]属性定义的。现在我的光标离开文本框,没有输入任何值,然后用户名属性触发属性更改通知(INotifyPropertyChanged), 但不要用红色边框标记我的文本框(位于用户控件内)。 下面是我的用户控件的代码 RestrictedBox.xaml <Grid x:Name="LayoutRoot

我创建了包含TextBox和PasswordBox的自定义用户控件。我还将TextBox绑定到用户名和PasswordBox。 用户名是在我的LoginViewModel类中用[Required]属性定义的。现在我的光标离开文本框,没有输入任何值,然后用户名属性触发属性更改通知(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>
<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

<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>
<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"  />
LoginViewModel.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
    }
[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
    }
 [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
    }
有人知道为什么我的自定义用户控件中的文本框没有包围红色边框吗?

任何帮助、建议和评论都将不胜感激

谢谢


Imdadhusen

正如我已经说过的,验证只对一个绑定有效,不会像您的情况那样被后续的bindign继承

最简单的方法是将
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
界面。

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

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

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

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

验证是在整个控件上进行的,而不是组成该控件的单个组件。您能否深入解释一下,因为我不清楚您在说什么。感谢您的及时回复。您需要在控件上创建一个依赖项属性,并将数据绑定到该属性。然后在内部将该属性的相应属性绑定到各个控件。在绑定中包含验证,红色框应该显示在正确的位置。是的,但是我已经实现了依赖属性。请指出我应该在哪里更改上述代码。再次感谢您的考虑。验证应用于用户控件,而不是文本框。这意味着当模型无效时,将在用户控件上引发验证错误事件,但它没有相应的可视状态。今天我将尝试复制您的问题,也许我会找到解决此问题的最佳方法。感谢您的完整解释,非常感谢。但是validation属性并不固定。因为这个自定义控件是完全动态的,所以,如果某个时间值字段不需要,而某个时间可能需要,您可以绑定任何模型。那么你能给我解释一下同样的方法吗?@imdadhusen在你的例子中,数据注释是最糟糕的解决方案,我不确定在你这样的场景中是否可能使用它们。将控件重写为临时控件或使用INotifyDataErrorInfo接口。感谢您的持续支持。让我找一个替代方案。我投+1票