WPF 验证和控制文本框样式

4

我使用基于属性的验证为WPF构建了自己的自定义验证框架。我卡在了最后一步上,即如何突出显示文本框。实际上,它确实可以突出显示文本框,但所有文本框都依赖于一个单一属性HasError。

public class RegistrationViewModel  : ViewModel
    {
        [NotNullOrEmpty("FirstName should not be null or empty")] 
        public string FirstName { get; set; }

        [NotNullOrEmpty("Middle Name is required!")]
        public string MiddleName { get; set; } 

        [NotNullOrEmpty("LastName should not be null or empty")] 
        public string LastName { get; set; }

        public bool HasError
        {
            get
            {
                **return Errors.Count > 0; // THIS IS THE PROBLEM** 
            }
        }

    }

以下是XAML代码:

 <Style x:Key="textBoxStyle" TargetType="{x:Type TextBox}">                   

            <Style.Triggers>

                <DataTrigger Binding="{Binding Path=HasError}" Value="True">
                    <Setter Property="Background" Value="Red" />
                </DataTrigger>

            </Style.Triggers>

        </Style>

以上代码的问题在于,它会突出显示所有使用“textBoxStyle”的文本框,即使它们是有效的。这是因为HasError并不是基于单个属性进行验证,而是整体验证。
有任何想法吗?
更新1:
ViewModel 包含 Errors 集合:
 public class ViewModel : ContentControl, INotifyPropertyChanged
    {
        public static DependencyProperty ErrorsProperty; 

        static ViewModel()
        {
            ErrorsProperty = DependencyProperty.Register("Errors", typeof(ObservableCollection<BrokenRule>), typeof(ViewModel)); 
        }

        public ObservableCollection<BrokenRule> Errors
        {
            get { return (ObservableCollection<BrokenRule>)GetValue(ErrorsProperty); }
            set 
            { 
                SetValue(ErrorsProperty,value);
                OnPropertyChanged("HasError");
             }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

    }

更新2:
我的验证引擎:
public bool Validate(object viewModel)
        {
            _brokenRules = new List<BrokenRule>();

            // get all the properties 

            var properties = viewModel.GetType().GetProperties(); 

            foreach(var property in properties)
            {
                // get the custom attribute 

                var attribues = property.GetCustomAttributes(typeof (EStudyValidationAttribute), false); 

                foreach(EStudyValidationAttribute att in attribues)
                {
                    bool isValid = att.IsValid(property.GetValue(viewModel,null));

                    if(isValid) continue; 

                    // add the broken rule 

                    var brokenRule = new BrokenRule()
                                         {
                                             PropertyName = property.Name,
                                             Message = att.Message
                                         }; 

                    _brokenRules.Add(brokenRule);
                }

            }

            var list = _brokenRules.ToObservableCollection(); 

            viewModel.GetType().GetProperty("Errors").SetValue(viewModel,list,null);

            return (_brokenRules.Count() == 0); 
        }

错误是一种集合吗? - Tony The Lion
2个回答

6

您可以在ViewModels中实现IDataErrorInfo接口,在XAML中检查带有验证错误的控件元素的附加属性Validation.HasError。这是更好的方法,因为它是.Net中的标准机制。

<Style x:Key="textBoxStyle" TargetType="{x:Type TextBox}">                   

            <Style.Triggers>

                <DataTrigger Binding="{Binding Path=Validation.HasError}" Value="True">
                    <Setter Property="Background" Value="Red" />
                </DataTrigger>

            </Style.Triggers>

        </Style>

绑定文本框中的属性时,需要将绑定 ValidatesOnDataError 属性设置为 true。
<TextBox x:Name="someTextBox" Text="{Binding Path=someProperty, ValidatesOnDataErrors=True}">



public class ViewModel : ContentControl, INotifyPropertyChanged,IDataErrorInfo
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

        public string this[string propertyName]
        {
            get
            {
                return ValidateProperty(this,propertyName);
            }
        }

        public string Error
        {
            get
            {
                            return "";
            }
        }

    }

你甚至可以使用你实现的验证方法,但是按属性检查验证。

我不想使用IDataErrorInfo,因为你需要编写大量代码来执行验证。我正在使用自己的自定义属性进行验证。请查看更新后的代码! - azamsharp
请查看此问题 => http://stackoverflow.com/questions/2164274/multidatatrigger-binding-to-collection-and-to-a-property-within-the-collection - azamsharp
你觉得实现IDataErrorInfo接口有什么难点呢?其实只需要几个属性,而且看起来你已经创建了所有必要的后备数据,但是你没有充分利用它与WPF内置集成的优势,反而手动完成了所有操作。 - John Bowen
IDataErrorInfo的问题在于我无法使用基于属性的验证。如果我有10个属性,那么我必须为这10个属性执行相同的验证。我更喜欢用一行属性装饰我的属性。 - azamsharp
我错过了什么吗?我得到了 BindingExpression 路径错误:'Validation' 属性未找到,我使用 Caliburn。 - user39880
显示剩余2条评论

0

你可能会对WPF应用程序框架(WAF)和示例应用程序BookLibraryEmailClient感兴趣。它们使用来自DataAnnotations命名空间的验证属性以及IDataErrorInfo接口。在经过验证的类中,您只需要添加两行额外的代码即可使其工作(例如:BookLibrary.Domain / Book.cs)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接