WPF Datagrid新行验证

时间:2011-07-06 14:40:17

标签: c# .net wpf validation datagrid

我使用DataGrid创建了一个简单的WPF应用程序,并将其绑定到带有Employee对象的List:

public class Employee
{
    private string _name;

    public int Id { get; set; }


    public string Name
    {
        get { return _name; }
        set
        {
            if (String.IsNullOrEmpty(value))
                throw new ApplicationException("Name cannot be empty. Please specify the name.");
            _name = value;
        }
    }

如您所见,我想阻止创建没有设置Name属性的Employees。 所以,我做了一个验证规则:

public class StringValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        string str = value as string;
        if (String.IsNullOrEmpty(str))
            return new ValidationResult(false, "This field cannot be empty");
        else
            return new ValidationResult(true, null);
    }
}

XAML for Name字段如下:

<DataGridTextColumn Header="Name" 
                                ElementStyle="{StaticResource datagridElStyle}" >
                <DataGridTextColumn.Binding>
                    <Binding Path="Name" Mode="TwoWay" NotifyOnValidationError="True" ValidatesOnExceptions="True" UpdateSourceTrigger="PropertyChanged" >
                        <Binding.ValidationRules>
                            <emp:StringValidationRule/>
                        </Binding.ValidationRules>
                    </Binding>
                </DataGridTextColumn.Binding>
            </DataGridTextColumn>

如果我尝试在DataGrid中编辑现有员工行的名称并将其设置为空字符串,则datagrid会标记错误的字段,并且不允许保存行。这是正确的行为。

但是如果我创建一个新行并按下键盘上的Enter键,则会在_name设置为NULL的情况下创建此新行,并且验证不起作用。我想这是因为DataGrid为新行对象调用默认构造函数并将_name字段设置为NULL。

验证新行的正确方法是什么?

2 个答案:

答案 0 :(得分:3)

您可以在IDataError对象上实施Employee。这个here有一个很好的页面。

答案 1 :(得分:0)

我实际上遇到了同样的问题,但因为我一直在使用Karl Shifflett所示的MVC数据注释:http://bit.ly/18NCpJU。我最初认为这是一个好主意,但我现在意识到微软可能不会包含MVC数据注释,因为这些似乎更适合提交表单,但不是数据持续存在且可以跨越会议,但我离题..

这是我为临时解决方案所做的事情。长期解决方案是实现IDataError:

// BusinessEntityBase is what allows us to
// use MVC Data Annotations ( http://bit.ly/18NCpJU )
public class MyModel : BusinessEntityBase
{
    private string _name;
    private List<Action> _validationQueue = new List<Action>();
    private Timer _timer = new Timer { Interval = 500 };

    [Required( AllowEmptyStrings = false )]
    public string Name
    {
        get
        {
            return this._name;
        }
        set
        {
            var currentValue = this._name;
            this._name = value;
            base.RaisePropertyChanged("Name");

            this.AddValidationAction( "Name", currentValue, value  );
        }
    }

    private void AddValidationAction<T>( string Name,  T currentValue, T newValue)
    {
        Action validationAction = 
            () => 
                base.SetPropertyValue( Name, ref currentValue, newValue );
        _validationQueue.Add(validationAction);
        this._timer.Enabled = true;
    }

    private void ProcessValidationQueue(object sender, ElapsedEventArgs e)
    {
        if( _validationQueue.Count > 0 )
        {
            while ( _validationQueue.Count > 0)
            {
                _validationQueue[0].Invoke();
                _validationQueue.RemoveAt( 0 );
            }
        }

        this._timer.Enabled = false;
    }

    public MyModel()
    {
        _timer.Enabled = false;
        _timer.Elapsed += this.ProcessValidationQueue;
        _timer.Start();
    }
}