c# – 如何在WPF应用程序中显示错误消息?
我正在尝试使用
WPF创建一个应用程序.我正在尝试使用MVVM模型完全构建它.但是,我很困惑如何正确显示错误消息.我认为这将是微不足道的一步,但似乎是最复杂的.
我使用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 所以我尝试将以下代码添加到App.xaml文件中 <!-- 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> 但是这没有显示错误消息,也是在第一次加载视图时我得到一个错误.最后,即使表单生效,操作按钮也会保持禁用状态. 更新 解决方法
我会尽力回答你的所有问题:
如何正确显示错误? 不应用ErrorTemplate,因为TextBox上的FormControl样式优先于包含Validation.ErrorTemplate的样式.将Validation.ErrorTemplate代码移动到FormControl样式将解决此问题. 另外,如何在首次加载视图时不显示任何错误? 如果不立即应用,必要验证的用途是什么?只有在开始键入字段时才会执行MinLength和MaxLength验证. 但是,错误消息似乎是通过按钮而不是按下按钮. 正如Will指出的那样,这是因为错误消息显示在AdornerLayer上,它不会干扰控件所在的层.您有以下选择: >使用AdornerLayer但在控件之间留出一些空间 这些选项描述为here (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |