Search code examples
c#wpfvalidationxamldatagridcell

How to continue working although a validation error in a DataGridCell occured?


I would like to display some values in a DataGrid. One column shall display integer values. When the user enters non-digit characters I want to tell this to the user but this value may be persisted though. Currently I am using a ValidationTemplate for a DataGridRow. The problem is that the complete row...the complete DataGrid is uneditable anymore until an integer value is entered in the particular cell. How can I achieve it to inform the user that he entered a wrong vlaue but allow this in the end?

Here's the style I am currently using:

<Style x:Key="errorRowStyle" TargetType="{x:Type DataGridRow}">
    <Setter Property="ValidationErrorTemplate">
        <Setter.Value>
            <ControlTemplate>
                <Grid>
                    <Ellipse Width="12" Height="12" Fill="Red" Stroke="Black" StrokeThickness="0.5"/>
                    <TextBlock FontWeight="Bold" Padding="4,0,0,0" Margin="0" VerticalAlignment="Top" Foreground="White" Text="!" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="BorderBrush" Value="Red"/>
            <Setter Property="IsEnabled" Value="True" />
            <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0]}"/>
        </Trigger>
    </Style.Triggers>
</Style>

Update 2018-01-13:

DataGrid: On cell validation error other row cells are uneditable/Readonly

is very close to my problem but it does not solve the problem that the entered (invalid) value is not put through to the ObservableCollection bound (twoway) to the cell with the invalid (alphanumeric) value (which is in fact a string property but the validator validates against an integer value) but a valid integer value is. (As I mentioned: the GUI is rather tolerant than restrict and shall give the user a hint and visualize that the entered value does not meet the requirements but even this invalid value shall be accepted.)

Can the validator be the reason??

namespace ConfigTool.Tools
{
    public class CycleValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value,
            System.Globalization.CultureInfo cultureInfo)
        {
            //DataRowView dataRowView = (value as BindingGroup).Items[0] as DataRowView;
            //string no = Convert.ToString(dataRowView.Row[0]);

            if (int.TryParse(value.ToString(), out int i))
            {
                return new ValidationResult(true, null);
            }
            else
            {
                return new ValidationResult(false,
                    "Cycle should be an integer value.");
            }
        }
    }
}

Solution

  • This helped me to find a solution.

    I changed my ValidationRule class as follows:

    public class CycleValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value,
            System.Globalization.CultureInfo cultureInfo)
        {
            BindingGroup group = (BindingGroup)value;
            StringBuilder error = null;
            foreach (var item in group.Items)
            {
                IDataErrorInfo info = item as IDataErrorInfo;
                if (info != null)
                {
                    if (!string.IsNullOrEmpty(info.Error))
                    {
                        if (error == null)
                        {
                            error = new StringBuilder();
                        }
                        error.Append((error.Length != 0 ? ", " : "") + info.Error);
                    }
                }
            }
    
            if (error != null)
                return new ValidationResult(false, error.ToString());
            else
                return new ValidationResult(true, "");
    
        }
    }
    

    In the underlying entity class implement IDataErrorInfo this way (extract):

    string IDataErrorInfo.Error
        {
            get
            {
                StringBuilder error = new StringBuilder();
                if (!int.TryParse(Cycle.ToString(), out int i))
                {
                    error.Append("Cycle should be an integer value.");
                }
    
                return error.ToString();
            }
        }
    

    In the XAML file I added

    <DataGrid.RowValidationRules>
        <local:CycleValidationRule ValidationStep="UpdatedValue" />
    </DataGrid.RowValidationRules>
    

    to the DataGrid.