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" />
2
  • Possible duplicate here: stackoverflow.com/questions/231052/… Commented Jun 28, 2011 at 16:12
  • 2
    the posts over there don't answer the question... Commented Jun 28, 2011 at 16:27

5 Answers 5

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.

Sign up to request clarification or add additional context in comments.

5 Comments

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. Without them, you will get a System.Windows.Data Warning: 40 : BindingExpression path error just like I had.
@S.Mishra what if i have two textboxes? Edit: NVM. Just only add almost identical line condition binding.
@p__d I believe you can add more <Condition> under <MultiDataTrigger.Conditions> section. Each for every input control.
Well, what if i have ItemsControl of n textboxes with a validation?
@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?
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();
    }
}

1 Comment

Worked great. Like this 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;

    }
}

Comments

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;

Comments

-1

just have a look at this linl

Disable Save button in WPF if validation fails

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.