Disabling button on Validation error

31,641

Solution 1

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.

Solution 2

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();
    }
}

Solution 3

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;

    }
}
Share:
31,641
anderi
Author by

anderi

Updated on September 06, 2021

Comments

  • anderi
    anderi over 2 years

    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" />