I'm working on a WPF-application in which I'm doing validation with IDataErrorInfo and validation rules. For disabling the save-button while there are still data errors at runtime, I have made a style:
<!--Disabling the Save-button by style not viewmodel-property-->
<Style x:Key="isEnabled_save_button" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tbx_firstname, Path=(Validation.HasError)}" Value="true">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tbx_lastname, Path=(Validation.HasError)}" Value="true">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tbx_age, Path=(Validation.HasError)}" Value="true">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
This works fine, but it's a little bit complicated because I have to check each control which is to validate. So I tried to write a generic data trigger:
<!--Disabling the Save-button by style not viewmodel-property-->
<Style x:Key="isEnabled_save_button" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(Validation.HasError), RelativeSource={RelativeSource AncestorType=Window}}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
But this doesn't work. How can I make it generic?
The Validation.HasError
attached property gets set individually for each element that is bound to a source property so there is no way to make some "generic" binding in the style of the Button.
What you should do is to bind the IsEnabled property of the Button to a property of your view model. It is the view model - the class that actually implements the IDataErrorInfo
interface - that should decide whether the button should be enabled based on your validation logic.
<Button IsEnabled="{Binding IsEnabled}" />
If you implement the INotifyDataErrorInfo
interface that was introduced in the .NET Framework 4.5 you could simply bind to the HasErrors
property:
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding HasErrors}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
There is more information and an example of how you could implement this interface available here: https://social.technet.microsoft.com/wiki/contents/articles/19490.wpf-4-5-validating-data-in-using-the-inotifydataerrorinfo-interface.aspx
If you are still on .NET 4 or/and choose to implement the old IDataErrorInfo
interface you could still add an HasErrors property to your view model that you set to true/false according to your validation logic. Don't forget to raise the PropertyChanged interface when you set the source property to a new value.