0

I have some problems with disabling one button if some controls inside a ListView have validation errors. It works for me when i check for errors directly from a control out of a ListView. Like in code below:

<Button.Style>
                    <Style TargetType="Button" BasedOn="{StaticResource MaterialDesignRaisedButton}">
                        <Setter Property="IsEnabled" Value="False" />
                        <Style.Triggers>
                            <MultiDataTrigger>
                                <MultiDataTrigger.Conditions>
                                    <Condition Binding="{Binding Path=(Validation.HasError), ElementName=TextBoxName}" Value="False" />                                        
                                </MultiDataTrigger.Conditions>
                                <Setter Property="IsEnabled" Value="True" />
                            </MultiDataTrigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>

And the control has:

<TextBox Name="TextBoxName"
                m:HintAssist.Hint="Title"
                m:HintAssist.IsFloating="True">
                <TextBox.Text>
                    <Binding Mode="TwoWay" Path="Test.Item1.Name" UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <local:NotEmptyValidationRule ValidatesOnTargetUpdated="True" />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>

So this works for me. But when i want to look inside of a ListView that has 6 controls(textboxes and comboboxes), i need to check if only two of them have errors.

How to find if only two controls from inside of a ListView have errors?

PS: I am using MVVM pattern. ListView has ItemTemplate, DataTemplate, and inside - controls like TextBox and ComboBox:

<ListView Name="ListViewTests" HorizontalAlignment="Center" Grid.Row="1" ItemsSource="{Binding SelectedActiveTests}"
                  ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                  ScrollViewer.VerticalScrollBarVisibility="Auto"
                  ScrollViewer.CanContentScroll="False">
            <ListView.ItemTemplate>
                <DataTemplate>

Please help, and sorry for my bad english...

BAndrei
  • 199
  • 2
  • 11

1 Answers1

2

one solution to your problem is to use a Command. When you bind a RelayCommand to your button, it automatically gets disabled if CanExecute returns false. So you can do your validation in the CanExecute method of your command. Something like this:

MyCommand = new RelayCommand(arg => ExecuteCommandAction(), arg => IsValid())

Update

Note that I used Microsoft EnterpriseLibrary for Validation! (https://msdn.microsoft.com/en-us/library/ff664451(v=pandp.50).aspx)

Define a command that checks for validation errors:

SaveAndCloseCommand = new RelayCommand(SaveAndCloseCommandExecute, arg => this.IsValid());

IsValid is a ViewModel method:

public bool IsValid()
{
    var validator = ValidationFactory.CreateValidator<YourViewModel>();
    return validator.Validate(this).IsValid;
}

Bind to your button:

<Button x:Name="SaveAndCloseButton" Command="{Binding SaveAndCloseCommand}" />

Your ViewModel has to contain validated properties like this:

[ValidatorComposition(CompositionType.And)]
[StringLengthValidator(1, 100)]
[RegexValidator(@"[^ ]")]
public string FirstName { ... }

TextField looks like this:

<TextBox Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}"             
         vab:Validate.ValidatesOnTargetUpdated="True" 
         vab:Validate.BindingForProperty="Text" />

Possible IsValid method to check your list items:

public bool IsValid()
{
    var allListItemsValid = myList.All(x => x.IsValid());   

    var validator = ValidationFactory.CreateValidator<YourViewModel>();
    return validator.Validate(this).IsValid && allListItemsValid;
}

Your list items should be ViewModels wich contains its validation, so you can check each item whether its valid or not.

S. Spindler
  • 546
  • 3
  • 12
  • Also, i need to enable and disable the button in the UI - on property change of those two controls. So i think this solution that you provided is not actual... I need to link somehow the ListViewItem if passes the validation rule on property change of the controls inside the ListViewItem, then enable the Button, and disable it if is not passing the validation rule – BAndrei Jan 19 '18 at 12:13
  • A solution could be if we could find the Child Control of ListViewItem. We can call the ListView - "ListV", and then to access by RelativeSource, FindAncestor, link to this name, and then to find inside the Child Control :) – BAndrei Jan 19 '18 at 12:34
  • You don't need to change the buttons state manually in your validation process. As mentioned, the CanExecute method determines whether the button is enabled or disabled. There you have to define the condition(s) that enables/disables the button. – S. Spindler Jan 19 '18 at 12:48
  • Using a command, you can call `myCommand.RaiseCanExecuteChanged()` to re-evaluate `CanExecute` if properties affecting it have changed. – Roger Leblanc Jan 19 '18 at 13:15
  • @S.Spindler . This method works for MVVM pattern, right? – BAndrei Jan 19 '18 at 13:25
  • @BAndrei Yes, I think this is the way to go with mvvm. – S. Spindler Jan 19 '18 at 14:05
  • @S.Spindler . Can you give Some Code Sample please? – BAndrei Jan 19 '18 at 14:23
  • @S.Spindler. Thank you. But now, if we have this TextBox inside the ListView? We have for example 3 items, each of them contains TextBox control. Also, ListView has as ItemSource=List So TextBox is just one of the properties of the CLASS. You think this will work? – BAndrei Jan 19 '18 at 14:49