我使用xaml创建了以下视图
<StackPanel Style="{StaticResource Col}"> <DockPanel> <Grid DockPanel.Dock="Top"> <Grid.ColumnDeFinitions > <ColumnDeFinition Width="*" ></ColumnDeFinition> <ColumnDeFinition Width="*"></ColumnDeFinition> </Grid.ColumnDeFinitions> <StackPanel Grid.Column="0" Style="{StaticResource Col}"> <Label Content="Name" Style="{StaticResource Formlabel}" /> <Border Style="{StaticResource FormInputBorder}"> <TextBox x:Name="Name" Style="{StaticResource FormControl}" Text="{Binding Name,ValidatesOnDataErrors=True,NotifyOnValidationError=True,UpdateSourceTrigger=PropertyChanged}" /> </Border> </StackPanel> <StackPanel Grid.Column="1" Style="{StaticResource Col}"> <Label Content="Phone Number" Style="{StaticResource Formlabel}" /> <Border Style="{StaticResource FormInputBorder}"> <TextBox x:Name="Phone" Style="{StaticResource FormControl}" Text="{Binding Phone,UpdateSourceTrigger=PropertyChanged}" /> </Border> </StackPanel> </Grid> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <Button Style="{StaticResource PrimaryButton}" Command="{Binding Create}">Create</Button> <Button>Reset</Button> </StackPanel> </DockPanel> </StackPanel>
然后我创建了以下viewmodel
public class vendorviewmodel : viewmodel { protected readonly IUnitOfWork UnitOfWork; private string _Name { get; set; } private string _Phone { get; set; } public vendorviewmodel() : this(new UnitOfWork()) { } public vendorviewmodel(IUnitOfWork unitOfWork) { UnitOfWork = unitOfWork; } [required(ErrorMessage = "The name is required")] [MinLength(5,ErrorMessage = "Name must be more than or equal to 5 letters")] [MaxLength(50,ErrorMessage = "Name must be less than or equal to 50 letters")] public string Name { get { return _Name; } set { _Name = value; NotifyPropertyChanged(); } } public string Phone { get { return _Phone; } set { _Phone = value; NotifyPropertyChanged(); } } /// <summary> /// Gets the collection of customer loaded from the data store. /// </summary> public ICollection<vendor> vendors { get; private set; } protected void Addvendor() { var vendor = new vendor(Name,Phone); UnitOfWork.vendors.Add(vendor); } public ICommand Create { get { return new ActionCommand(p => Addvendor(),p => IsValidRequest()); } } public bool IsValidRequest() { // There got to be a better way to check if everything passed or Now... return IsValid("Name") && IsValid("Phone"); } }
这是我的viewmodel基类的样子
public abstract class viewmodel : ObservableObject,IDataErrorInfo { /// <summary> /// Gets the validation error for a property whose name matches the specified <see cref="columnName"/>. /// </summary> /// <param name="columnName">The name of the property to validate.</param> /// <returns>Returns a validation error if there is one,otherwise returns null.</returns> public string this[string columnName] { get { return OnValidate(columnName); } } /// <summary> /// Validates a property whose name matches the specified <see cref="propertyName"/>. /// </summary> /// <param name="propertyName">The name of the property to validate.</param> /// <returns>Returns a validation error,if any,otherwise returns null.</returns> protected virtual string OnValidate(string propertyName) { var context = new ValidationContext(this) { MemberName = propertyName }; var results = new Collection<ValidationResult>(); bool isValid = Validator.TryValidateObject(this,context,results,true); if (!isValid) { ValidationResult result = results.SingleOrDefault(p => p.MemberNames.Any(memberName => memberName == propertyName)); if (result != null) return result.ErrorMessage; } return null; } protected virtual bool IsValid(string propertyName) { return OnValidate(propertyName) == null; } /// <summary> /// Not supported. /// </summary> [Obsolete] public string Error { get { throw new NotSupportedException(); } } }
这是我的ObservableObject类
public class ObservableObject : INotifyPropertyChanged { /// <summary> /// Raised when the value of a property has changed. /// </summary> public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// Raises <see cref="PropertyChanged"/> for the property whose name matches <see cref="propertyName"/>. /// </summary> /// <param name="propertyName">Optional. The name of the property whose value has changed.</param> protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this,new PropertyChangedEventArgs(propertyName)); } } }
我的目标是在不正确的字段周围显示一个红色边框,然后在它下面显示错误消息,告诉使用出了什么问题.
如何正确显示错误?另外,如何在首次加载视图时不显示任何错误?
基于此blog,我需要编辑Validation.ErrorTemplate
<!-- Style the error validation by showing the text message under the field --> <Style targettype="TextBox"> <Setter Property="Validation.ErrorTemplate"> <Setter.Value> <ControlTemplate> <StackPanel> <Border BorderThickness="1" BorderBrush="DarkRed"> <StackPanel> <AdornedElementPlaceholder x:Name="errorControl" /> </StackPanel> </Border> <TextBlock Text="{Binding AdornedElement.ToolTip,ElementName=errorControl}" Foreground="Red" /> </StackPanel> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="Validation.HasError" Value="true"> <Setter Property="BorderBrush" Value="Red" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent}" /> </Trigger> </Style.Triggers> </Style>
但是这没有显示错误消息,也是在第一次加载视图时我得到一个错误.最后,即使表单生效,操作按钮也会保持禁用状态.
更新
将Property =“Validation.ErrorTemplate”移动到FormControl组后,它工作了.但是,错误消息似乎是通过按钮而不是按下按钮.此外,文本似乎没有垂直包装,允许边框覆盖其他控件,如下面的屏幕显示所示.
解决方法
不应用ErrorTemplate,因为TextBox上的FormControl样式优先于包含Validation.ErrorTemplate的样式.将Validation.ErrorTemplate代码移动到FormControl样式将解决此问题.
如果不立即应用,必要验证的用途是什么?只有在开始键入字段时才会执行MinLength和MaxLength验证.
但是,错误消息似乎是通过按钮而不是按下按钮.
正如Will指出的那样,这是因为错误消息显示在AdornerLayer上,它不会干扰控件所在的层.您有以下选择:
>使用AdornerLayer但在控件之间留出一些空间
>使用工具提示显示错误消息
>在TextBox的模板中使用额外的TextBlock,以显示错误消息.
这些选项描述为here
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。