简体   繁体   English

在窗口加载时调用验证,WPF 使用 INotifyDataErrorInfo

[英]Call validation on when window loads, WPF using INotifyDataErrorInfo

I have model named EditableSong which is derived from ValidatableModel Class which implements INotifyPropertyChanged and INotifyDataErrorInfo .我有一个名为EditableSong模型,它派生自实现INotifyPropertyChangedINotifyDataErrorInfo ValidatableModel类。

class EditableSong : ValidatableModel
{
    CommandRelay addcommand = null;

    public ICommand AddCommand
    {
        get { return addcommand; }
    }

    public EditableSong()
    {
        addcommand = new CommandRelay(Add, CanAdd);
    }

    private void Add(object obj = null)
    {
        MessageBox.Show("Succesfully Added!");
    }

    private bool CanAdd(object obj = null)
    {
        return !HasErrors;
    }

    private string title;
    [Required]
    [MaxLength(45)]
    public string Title
    {
        get { return title; }
        set
        { SetProperty(ref title, value); }
    }

    private string lyrics;
    [MaxLength(3000)]
    public string Lyrics
    {
        get { return lyrics; }
        set { SetProperty(ref lyrics, value); }
    }

    private string artist;

    [Required]
    public string Artist
    {
        get { return artist; }
        set {SetProperty(ref artist, value); }
    }
}

And here is ValidatableModel class:这是ValidatableModel类:

class ValidatableModel : BindableBase, INotifyDataErrorInfo
{
    private Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>();

    public bool HasErrors
    {
        get  { return _errors.Count >0; ; }
    }

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    protected override void SetProperty<T>(ref T member, T val,
         [CallerMemberName] string propertyName = null)
    {

        base.SetProperty(ref member, val, propertyName);
        ValidateProperty(propertyName, val);
    }

    public IEnumerable GetErrors(string propertyName)
    {
        if (_errors.ContainsKey(propertyName))
            return _errors[propertyName];
        else
            return null;
    }

    protected void ValidateProperty<T>(string propertyName, T value)
    {

        var results = new List<ValidationResult>();

        ValidationContext context = new ValidationContext(this);
        context.MemberName = propertyName;
        Validator.TryValidateProperty(value, context, results);

        if (results.Any())
        {
            _errors[propertyName] = results.Select(c => c.ErrorMessage).ToList();
        }
        else
        {
            _errors.Remove(propertyName);
        }

        ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
    }

    protected void OnErrorsChanged(string propName)
    {
        ErrorsChanged(this, new DataErrorsChangedEventArgs(propName));
    }
}`

And it works well, but only after I change properties in textboxes of my window.它运行良好,但只有在我更改窗口文本框中的属性之后。 The main problem is that user mustn't be able to save model without filling required fields, but when windows loads button Save (which uses command) available, because of validation doesn't run.主要问题是用户不能在不填写必填字段的情况下保存模型,但是当 Windows 加载按钮保存(使用命令)可用时,因为验证没有运行。

Here is xaml:这是xaml:

<Window x:Class="ValidationTests.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ValidationTests"
    xmlns:rules="clr-namespace:ValidationTests.Rules"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Window.Resources>
    <Style x:Key="TextBoxError" TargetType="{x:Type TextBox}">
        <Setter Property="Validation.ErrorTemplate">
            <Setter.Value>
                <ControlTemplate x:Name="TextErrorTemplate">
                    <DockPanel LastChildFill="True">
                        <AdornedElementPlaceholder>
                            <Border BorderBrush="Red" BorderThickness="2"/>
                        </AdornedElementPlaceholder>
                    </DockPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <StackPanel>
        <Label>Artist</Label>
        <TextBox Style="{StaticResource TextBoxError}" Text="{Binding Artist,
            ValidatesOnNotifyDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        </TextBox>
        <Label>Title</Label>
        <TextBox Style="{StaticResource TextBoxError}" Text="{Binding Title,
            ValidatesOnNotifyDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
        <Label>Lyrics</Label>
        <TextBox Style="{StaticResource TextBoxError}" Text="{Binding Lyrics,
            ValidatesOnDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
        <Button Content="Add" Command="{Binding AddCommand}"></Button>
    </StackPanel>
</Grid>

I wonder how can i fix this...我想知道我该如何解决这个问题...

I wonder how can i fix this...我想知道我该如何解决这个问题...

You need to perform the actual validation upfront.您需要预先执行实际的验证。

Call the ValidateProperty method for all properties in the constructor of your EditableSong class to populate the Dictionary and raise the ErrorsChanged event:EditableSong类的构造函数中为所有属性调用ValidateProperty方法以填充Dictionary并引发ErrorsChanged事件:

public EditableSong()
{
    addcommand = new CommandRelay(Add, CanAdd);

    ValidateProperty(nameof(Title), title);
    ValidateProperty(nameof(Lyrics), lyrics);
    ValidateProperty(nameof(Artist), artist);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM