0
votes

I've a datagrid bound to datatable. Number of columns are decided during runtime. I'm using Datagrid.RowValidationRule to validate contents of cell after edit. A style is used to highlight the row with red border in case of error.

Is it possible to highlight only the cells having invalid data with red border instead of highlighting complete row?

Binding:

 ItemsSource="{Binding Path=., ValidatesOnExceptions=True, NotifyOnValidationError=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" 
                                  AutoGenerateColumns="True"

Validation:

<DataGrid.RowValidationRules>
                                <local:RowDataValidationRule ValidationStep="UpdatedValue" ValidatesOnTargetUpdated="True"/>
                            </DataGrid.RowValidationRules>

Style:

 <Style x:Key="RowStyle" TargetType="{x:Type DataGridRow}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="BorderThickness" Value="2"/>
                <Setter Property="BorderBrush" Value="Red"/>
                <Setter Property="ToolTip"
   Value="{Binding RelativeSource={RelativeSource Self},
       Path=(Validation.Errors)[0].ErrorContent}"/>
            </Trigger>
        </Style.Triggers>
    </Style>

CodeBehind:

public class RowDataValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {

        BindingGroup group = (BindingGroup)value;

        StringBuilder error = null;
        foreach (var item in group.Items)
        {
            DataRowView rowView = item as DataRowView;
            if (rowView != null)
            {
               // Validation logic, sets error
            }
        }
        if (error != null)
            return new ValidationResult(false, error.ToString());
        return ValidationResult.ValidResult;
    }

}
1

1 Answers

1
votes

Sure, you can specify one or more validation rules for each column. Let's suppose you have a TextBox grid column binded to the "Description" DataColumn. So you can define your DataGridTextColumn in this way (look at "Binding" node)

<DataGridTextColumn Header="Description">
    <DataGridTextColumn.Binding>
        <Binding Path="[Description]">
            <Binding.ValidationRules>
                <local:MyValidationRule />
            </Binding.ValidationRules>
        </Binding>
    </DataGridTextColumn.Binding>
</DataGridTextColumn>

EDIT

Of course you can do the same by using code. You just need to add an event handler to your DataGrid:

<DataGrid AutoGenerateColumns="True" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" />

Then you will add your validation rule to the Binding in this way:

private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    Binding binding;
    DataGridTextColumn dataGridTextColumn = e.Column as DataGridTextColumn;
    if(dataGridTextColumn != null)
    {
        binding = new Binding(String.Concat("[", dataGridTextColumn.Header, "]"));
        binding.Mode = BindingMode.TwoWay;
        binding.ValidationRules.Add(new MyValidationRule());

        dataGridTextColumn.Binding = binding;
    }
}

Of course you have to add logic for considering other DataGrid column types.