views:

82

answers:

1

I am trying to get a validation rule to return an error. I implemented IDataErrorInfo in my model, which contains my business object properties and messages to return in the event validation fails. I also created a validation rule. The problem is, the validation rule is firing (bookmarked it) but the IDataErrorInfo reference in the rule never has an error, even though the IDataErrorInfo implementation of my model generates one. The datagrid definitely shows there was a validation failure.

I tested it by having the rule and model return two different messages, and the model's version is always returned. It is like my rule cannot see what is in the IDataErrorInfo object, or it is just creating a new instance of it.

DataGrid:

<DataGrid ItemsSource="{Binding Path=ProjectExpenseItemsCollection}" AutoGenerateColumns="False" 
    Name="dgProjectExpenseItems" RowStyle="{StaticResource RowStyle}" 
    SelectedItem="{Binding Path=SelectedProjectExpenseItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
    CanUserDeleteRows="True" CanUserAddRows="True">
    <DataGrid.RowValidationRules>
        <vr:RowDataInfoValidationRule ValidationStep="UpdatedValue" />
    </DataGrid.RowValidationRules>
    <DataGrid.Columns>
        <DataGridTextColumn Header="Item Number" 
            Binding="{Binding ItemNumber, Mode=TwoWay, 
            UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
    </DataGrid.Columns>
</DataGrid>

Validation Rule:

The object "idei" isn't null, but idei.Error is always a zero-length string ("")

public class RowDataInfoValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        BindingGroup bindingGroup = (BindingGroup)value;
        IDataErrorInfo idei = bindingGroup.Items[0] as IDataErrorInfo;
        string error = (idei != null) ? idei.Error : null; 
        return (string.IsNullOrEmpty(error)) ? ValidationResult.ValidResult : new ValidationResult(false, error + ": ValidationRule");
    }
}

Model/Business Object:

public class ProjectExpenseItemsBO : IDataErrorInfo, IEditableObject, INotifyPropertyChanged
{
    public string ItemNumber { get; set; }

    public ProjectExpenseItemsBO() {}

    // string method
    static bool IsStringMissing(string value)
    {
        return String.IsNullOrEmpty(value) || value.Trim() == String.Empty;
    }

    #region IDataErrorInfo Members

    public string Error
    {
        get { return this[string.Empty]; }
    }

    public string this[string propertyName]
    {
        get
        {
            string result = string.Empty;
            if (propertyName == "ItemNumber")
            {
                if (IsStringMissing(this.ItemNumber))
                {
                    result = "Item number cannot be empty-IDataError!";
                }
            }

            return result;
        }
    }

    #endregion
}
+1  A: 

The IDataErrorInfo object that the rule gets will be an instance of your ProjectExpenseItemsBO object. The only property you check is Error, which you have implemented to return this[string.Empty], which will always return string.Empty. You probably either want to change your implementation of the Error property to look at all the errors in the object, or to have RowDataInfoValidationRule iterate through properties and get the error message for each one through the indexer.

You are getting validation errors from the model because your binding to ItemNumber has ValidatesOnDataErrors set to True, so the framework will call the indexer with the property name ItemNumber and get your error message.

Quartermeister
that makes total sense, and I feel a little stupid for not seeing that (newbee). I added the code necessary to pass the error on and it is working! As for your second answer, even though my VR can access the error, the dg is still looking to the IDEI in the model for its message and validation result? How can I get the rule to override the IDEI in this case? I am trying to get the VR to clear the validation error in the dg when the error is fixed, but I can only do it if I sort or refresh the dg. I thought having the VR set the result to ValidResult would clear the error. BTW, Thanks!
steveareeno
Let me correct something. I don't necessarily want to override the error from IDEI in the model-that was really for testing purposes-what I want to do is clear the validation error in the grid when the user corrects the error, which does not happen unless I sort or refresh the dg.
steveareeno
Ok, I get it now. because the column in my dg has ValidatesOnDataErrors set to true, it will ignore the result of the VR. I removed it from the column and every is working fine now. I thought I could use them in conjunction with each other, but it appears it is an either/or thing. This was all about clearing the error from the dg when it was corrected. In this case, it appears the VR's can do it and IDEI cannot, at least not without refreshing the dg.
steveareeno
One more thing Quartermeister. I really want to thank you for your reply! I have been trying to solve this now for about two or three weeks.
steveareeno
@steveareeno: I think the DataGrid is has some bugs with handling validation. See http://wpf.codeplex.com/wikipage?title=Validation for a description of the issue. This article seems to have some workarounds, but I haven't actually tried them: http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx#validation.
Quartermeister
Thanks. I took a look at it and remember reading the same thing somewhere else (about using RawProposed value). I am using VS 2010 which I understand has its own dg (vs having to use the toolkit). Not sure if the problem is fixed in this version however.
steveareeno