30

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" />
anderi
  • 767
  • 2
  • 11
  • 18

5 Answers5

67

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.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
S.Mishra
  • 3,394
  • 28
  • 20
  • 13
    In case someone else doesn't know this like I didn't, you must have the parentheses around the `Validation.HasError` path. [That's how it refers to the attached property.](http://stackoverflow.com/a/14382796/1229237) Without them, you will get a `System.Windows.Data Warning: 40 : BindingExpression path error` just like I had. – DJH Mar 25 '15 at 14:16
  • 2
    @S.Mishra what if i have two textboxes? Edit: NVM. Just only add almost identical line condition binding. – p__d Oct 19 '16 at 09:40
  • 1
    @p__d I believe you can add more under section. Each for every input control. – S.Mishra Feb 06 '17 at 22:54
  • 1
    Well, what if i have `ItemsControl` of `n` textboxes with a validation? – Ignatii Marine Jan 30 '18 at 13:07
  • @S.Mishra Your suggested solution disables the button if there is an error. What one would like to have that by default button stays disabled and once the condition is satisfied it gets enabled. Currently you are allowing to submit the button even if there is nothing entered into the textbox. How would you achieve the scenario I just described? – nam Nov 09 '20 at 16:43
13

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();
    }
}
Athafoud
  • 2,898
  • 3
  • 40
  • 58
Saâd Haffar
  • 143
  • 1
  • 6
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;

    }
}
Lücks
  • 3,806
  • 2
  • 40
  • 54
0

If you use MVVM then just implement a method CanExecute of interface ICommand. Button doesn't become disabled when command CanExecute is false

If you write your logic in codebehind then just use a property of a button IsEnabled:

xaml:

<Button Name=_btn/>

SomeForm.xaml.cs:

_btn.IsEnabled=false;
Community
  • 1
  • 1
StepUp
  • 36,391
  • 15
  • 88
  • 148
-1

just have a look at this linl

Disable Save button in WPF if validation fails

Community
  • 1
  • 1
Kishore Kumar
  • 21,449
  • 13
  • 81
  • 113