Skip to main content Skip to footer

Apply Conditional Formatting to a DataGrid with ValidationStyleDecorator

Providing users with visual cues about data validation is an important part of any interface design. The ValidationStyleDecorator in DataGrid allows you to highlight, color, add alerts, and otherwise perform both validation and conditional formatting simultaneously. It is important to note that ValidationStyleDecorator can only be applied on a bound control because it applies the style by validating data at datasource level, i.e., through the bound collection. Let's walk through the steps.

Step One: Define a style to apply to the validation

First, we need to decide what styles we'll be applying. Here, we're defining two styles to show the validated data: tooltip style and validation decorator.

Tooltip Style



<!--<br/><Setter&nbsp;Property="Background"&nbsp;Value="{StaticResource&nbsp;ValidationBaseColorBrush}"&nbsp;/><br/><Setter&nbsp;Property="Foreground"&nbsp;Value="{StaticResource&nbsp;ValidationForegroundBrush}"&nbsp;/><br/><Setter&nbsp;Property="Template"><br/><Setter.Value><br/><ControlTemplate&nbsp;TargetType="ToolTip"><br/><Grid&nbsp;x:Name="Root"&nbsp;Margin="5&nbsp;0"><br/><Border&nbsp;Background="{TemplateBinding&nbsp;Background}"&nbsp;CornerRadius="2"><br/><ContentPresenter&nbsp;x:Name="Content"&nbsp;Content="{TemplateBinding&nbsp;Content}"&nbsp;ContentTemplate="{TemplateBinding&nbsp;ContentTemplate}"&nbsp;/><br/></Border><br/></Grid><br/></ControlTemplate><br/></Setter.Value><br/></Setter><br/>-->

Validation Decorator:



<!--<br/><Setter&nbsp;Property="Background"&nbsp;Value="{StaticResource&nbsp;ValidationBaseColorBrush}"&nbsp;/><br/><Setter&nbsp;Property="Foreground"&nbsp;Value="{StaticResource&nbsp;ValidationForegroundBrush}"&nbsp;/><br/><Setter&nbsp;Property="CornerRadius"&nbsp;Value="1"&nbsp;/><br/><Setter&nbsp;Property="BorderThickness"&nbsp;Value="1"&nbsp;/><br/><Setter&nbsp;Property="IsTabStop"&nbsp;Value="False"&nbsp;/><br/><Setter&nbsp;Property="IsHitTestVisible"&nbsp;Value="False"&nbsp;/><br/><Setter&nbsp;Property="Template"><br/><Setter.Value><br/><ControlTemplate&nbsp;TargetType="c1:C1ValidationDecorator"><br/><Border&nbsp;x:Name="ValidationErrorElement"&nbsp;BorderThickness="{TemplateBinding&nbsp;BorderThickness}"&nbsp;CornerRadius="{TemplateBinding&nbsp;CornerRadius}"&nbsp;BorderBrush="{TemplateBinding&nbsp;Background}"&nbsp;Visibility="Hidden"><br/><VisualStateManager.VisualStateGroups><br/><VisualStateGroup&nbsp;x:Name="ValidationStates"><br/><VisualState&nbsp;x:Name="Valid"&nbsp;/><br/><VisualState&nbsp;x:Name="InvalidUnfocused"><br/><Storyboard><br/><ObjectAnimationUsingKeyFrames&nbsp;Storyboard.TargetName="ValidationErrorElement"&nbsp;Storyboard.TargetProperty="Visibility"><br/><DiscreteObjectKeyFrame&nbsp;KeyTime="0"><br/><DiscreteObjectKeyFrame.Value><br/><Visibility>Visible </Visibility><br/></DiscreteObjectKeyFrame.Value><br/></DiscreteObjectKeyFrame><br/></ObjectAnimationUsingKeyFrames><br/></Storyboard><br/></VisualState><br/><VisualState&nbsp;x:Name="InvalidFocused"><br/><Storyboard><br/><ObjectAnimationUsingKeyFrames&nbsp;Storyboard.TargetName="ValidationErrorElement"&nbsp;Storyboard.TargetProperty="Visibility"><br/><DiscreteObjectKeyFrame&nbsp;KeyTime="0"><br/><DiscreteObjectKeyFrame.Value><br/><Visibility>Visible </Visibility><br/></DiscreteObjectKeyFrame.Value><br/></DiscreteObjectKeyFrame><br/></ObjectAnimationUsingKeyFrames><br/><ObjectAnimationUsingKeyFrames&nbsp;Storyboard.TargetName="validationTooltip"&nbsp;Storyboard.TargetProperty="IsOpen"><br/><DiscreteObjectKeyFrame&nbsp;KeyTime="0"><br/><DiscreteObjectKeyFrame.Value><br/><system:Boolean>True </system:Boolean><br/></DiscreteObjectKeyFrame.Value><br/></DiscreteObjectKeyFrame><br/></ObjectAnimationUsingKeyFrames><br/></Storyboard><br/></VisualState><br/></VisualStateGroup><br/></VisualStateManager.VisualStateGroups><br/><ToolTipService.ToolTip><br/><ToolTip&nbsp;x:Name="validationTooltip"&nbsp;Background="{TemplateBinding&nbsp;Background}"&nbsp;Foreground="{TemplateBinding&nbsp;Foreground}"&nbsp;Placement="Right"&nbsp;PlacementTarget="{TemplateBinding&nbsp;Target}"&nbsp;Style="{StaticResource&nbsp;ValidationToolTipStyle}"&nbsp;Content="{Binding&nbsp;RelativeSource={RelativeSource&nbsp;TemplatedParent},&nbsp;Path=Target.(Validation.Errors)}"><br/><ToolTip.ContentTemplate><br/><DataTemplate><br/><TextBlock&nbsp;Margin="8&nbsp;4"&nbsp;MaxWidth="250"&nbsp;VerticalAlignment="Center"&nbsp;Text="{Binding&nbsp;Path=[0].ErrorContent}"&nbsp;TextWrapping="Wrap"&nbsp;/><br/></DataTemplate><br/></ToolTip.ContentTemplate><br/></ToolTip><br/></ToolTipService.ToolTip><br/><Path&nbsp;Data="M&nbsp;1,0&nbsp;L6,0&nbsp;A&nbsp;2,2&nbsp;90&nbsp;0&nbsp;1&nbsp;8,2&nbsp;L8,7&nbsp;z"&nbsp;Fill="{TemplateBinding&nbsp;Background}"&nbsp;Margin="0&nbsp;-1&nbsp;-1&nbsp;0"&nbsp;HorizontalAlignment="Right"&nbsp;VerticalAlignment="Top"&nbsp;/><br/></Border><br/></ControlTemplate><br/></Setter.Value><br/></Setter><br/>-->

Step Two: Define Validation Conditions

So we've defined all the styles we want to apply while performing the validations. Now, we need to define our conditions. For this, we need to implement IDataErrorInfo interface:


public class Person : IDataErrorInfo  
{  
private int age;  
private string name;  
public int Age  
{  
get { return age; }  
set { age = value; }  
}  
public string Name  
{  
get { return name; }  
set { name = value; }  
}  
public string Error  
{  
get  
{return null;}  
}  
public string this[string name]  
{  
get  
{  
string result = null;  
if (name == "Age")  
{  
if (this.age < 0 || this.age > 50)  
{  
result = "Age must be less than 50";  
}  
}  
if (name == "Name")  
{  
if (this.name.Length < 3)  
result = "Too Small Name";  
}  
return result;  
}  
}  
}

Step Three: Apply Styles

The final step is to apply the styles using ValidationStyleDecorator.

Apply the styles in an appropriate event:


c1DataGrid1.BeganEdit += (s, e) =>  
{  
if (e.EditingElement is C1TextBoxBase)  
{  
var tb = e.EditingElement as C1TextBoxBase;  
tb.ValidationDecoratorStyle = this.Resources["vd"] as Style;  
var binding = tb.GetBindingExpression(C1TextBoxBase.C1TextProperty).ParentBinding;  
var newbinding = CopyBinding(binding);  
newbinding.NotifyOnValidationError = true;  
newbinding.ValidatesOnDataErrors = true;  
tb.SetBinding(C1TextBoxBase.C1TextProperty, newbinding);  
}  
if (e.EditingElement is C1NumericBox)  
{  
var nb = e.EditingElement as C1NumericBox;  
var binding = nb.GetBindingExpression(C1NumericBox.ValueProperty).ParentBinding;  
var newbinding = CopyBinding(binding);  
newbinding.NotifyOnValidationError = true;  
newbinding.ValidatesOnDataErrors = true;  
nb.SetBinding(C1NumericBox.ValueProperty, newbinding);  
}  
};

Copy the previous binding to the updated object in order to maintain data integrity:


private Binding CopyBinding(Binding CurrentBinding)  
{  
Binding NewBinding = new Binding();  
PropertyInfo[] fields = typeof(Binding).GetProperties();  
foreach (PropertyInfo pi in fields)  
{  
if ((pi.GetValue(CurrentBinding, null) != null) && (pi.CanWrite == true))  
pi.SetValue(NewBinding, pi.GetValue(CurrentBinding, null), null);  
}  
NewBinding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;  
return NewBinding;  
}

Conclusion

ValidationStyleDecorator enables us to apply the custom styles to the different sub-components within a single control. Also, it provides a way to perform validation on the bound data source.

See it in action!

Demo1 Download Sample >>

MESCIUS inc.

comments powered by Disqus