I have couple of textboxes with custom validators:
(I don't mind if "wrong" data is sent back to object (the property is string), I just need to prevent the functionality of a button if there is an error, so if the binding is not the right place for that kind of validation please tell. I just like the Validation.ErrorTemplate support that i can use)
<ControlTemplate x:Key="validator" >
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right" Foreground="Red" FontSize="12pt">!</TextBlock>
<Border BorderBrush="Red" BorderThickness="1.0">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
<TextBox Height="23" Width="150" TextWrapping="Wrap"
Validation.ErrorTemplate="{StaticResource validator}">
<TextBox.Text>
<Binding Path="StringProperty" UpdateSourceTrigger="LostFocus">
<Binding.ValidationRules>
<local:NumbersOnly/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
How can I disable specific button if any of the validation error is raised?
<Button Content="DO Work" Height="57" HorizontalAlignment="Left" Name="button1" VerticalAlignment="Top" Width="234" Click="button1_Click" />
You can use MultiDataTrigger
property in Style.Triggers
of Button
. Let's assume that we have a TextBox
named "txtName". We have to disable button "btnSave" on the validation error of TextBox
.
Here is what you can do:
<Button Content="Save"
Grid.Column="1"
Grid.Row="3"
HorizontalAlignment="Right"
Height="23"
Name="btnSave"
Width="75"
IsDefault="True"
Command="{Binding SaveProtocolCommand}"
Margin="3">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=txtName}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Hope this will help you.
CanExecute
in MVVM is for authorization management but people use it for validation. The best way is to do it in XAML. You will need a converter if you have multiple fields to validate (InverseAndBooleansToBooleanConverter
is my implementation for multiple Booleans values). Here is how to do so:
XAML code(I'm sorry if the XAML code does show because I could have it appear even if I tried):
<Button Name="Button_Test" Content="Test">
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource InverseAndBooleansToBooleanConverter}" Mode="TwoWay">
<Binding ElementName="TextBox_Field1" Path="(Validation.HasError)" />
<Binding ElementName="TextBox_Field2" Path="(Validation.HasError)" />
<Binding ElementName="TextBox_Field3" Path="(Validation.HasError)" />
</MultiBinding>
</Button.IsEnabled>
</Button>
The converter
public class InverseAndBooleansToBooleanConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values.LongLength > 0)
{
foreach (var value in values)
{
if (value is bool && (bool)value)
{
return false;
}
}
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Add this to your TextBlock:
Validation.Error="Save_Error"
CodeBehind (xaml.cs):
public partial class MyView : Window
{
private int _noOfErrorsOnScreen = 0;
public MyView()
{
InitializeComponent();
}
private void Save_Error(object sender, ValidationErrorEventArgs e)
{
if (e.Action == ValidationErrorEventAction.Added)
_noOfErrorsOnScreen++;
else
_noOfErrorsOnScreen--;
Save.IsEnabled = _noOfErrorsOnScreen > 0 ? false : true;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With