2
votes

I have a simple standard WPF 4 DataGrid with two columns.

<DataGrid ItemsSource="{Binding Source={StaticResource ItemDataView}}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Alpha">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Alpha}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Beta">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Beta}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

The data objects displayed are defined as so:

public class MyObject : INotifyDataErrorInfo
{
    [Required]
    public string Alpha { get; set; }

    public string Beta { get; set; }

    public bool HasErrors
    {
        get { return string.IsNullOrEmpty(Alpha); }
    }

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public IEnumerable GetErrors(string propertyName)
    {
        yield return propertyName;
    }
}

i.e. Alpha must have a non-empty value, but Beta can be null.

If I add a MyObject where the Alpha value is empty, then both the Alpha and Beta cells are given a red border indicating a validation error. This only happens for DataGridTemplateColumns; I've tried adding a DataGridTextColumn and it doesn't get the red border. The Beta column also gets a red border if it is not bound to anything, or even if it doesn't have a control attached (e.g. DataTemplate is empty).

a) Why does this happen?

b) How can I stop it happening? I only want the red validation border on the cell with the error.

1
your HasErrors function returns only an evaluation of Alpha. So the Beta cell will just mirror whatever the Alpha cell condition is.Paul Gibson

1 Answers

1
votes

INotifyDataErrorInfo is used to determine if there are errors. Specifically, the HasErrors property must be implemented to return true or false to denote if errors exist. In your case, the HasErrors implementation is only looking at Alpha:

public bool HasErrors
{
    get { return string.IsNullOrEmpty(Alpha); }
}

So it will only show that there are errors if Alpha is null or empty.

You'll need to modify that to check both, like this:

public bool HasErrors
{
    get 
    {
       return !AlphaIsValid || !BetaIsValid;
    }
}

private bool AlphaIsValid
{
    get {return !string.IsNullOrEmpty(Alpha);}
}

private bool BetaIsValid
{
    get {return Beta == null || Beta != "";}
}

Then, in GetErrors(), check the string that's passed in to see if it matches Alpha or Beta, and provide an error message for each, like this:

public IEnumerable GetErrors(string propertyName)
{
    if (propertyName == nameof(Alpha) && !AlphaIsValid)
    {
        return new []{"Alpha is null or empty"};
    }
    if (propertyName == nameof(Beta)  && !BetaIsValid)
    {
        return new []{"Beta is empty"};
    }
    return Enumerable.Empty<string>();
}

Return an empty collection if there are no errors for the property.

Currently, you're returning a value for both properties (in that you're just returning the property name back), so both are marked as having validation errors.

For Reference: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifydataerrorinfo(v=vs.110).aspx