Question How to bind a button from Errors of several TextBoxes?

Niso

New member
Joined
Nov 30, 2020
Messages
3
Programming Experience
1-3
hello everyone i'm new here and would like some help with something.

I wanted to ask how I bind a button so that as long as all the text boxes are not filled with legal content the button will be disabled, I want the binding to be according to the Errors of all the boxes. The thing is that I saw an example of this, with MultiDataTrigger.Conditions so that each Condition refers to a certain text box, the problem with the example is that its for a small amount of text boxes, I want to do it on 10 text boxes so that writing Conditions 10 times for each text box is inelegant and inefficient . Is there any way to write Conditions that will refer to all the text boxes of that are in the window?
Here is the code in brief (without all the binding of the errors associated with text boxes)

added code below:

C#:
<Window x:Class="WpfTextBoxValidation.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:WpfTextBoxValidation"

        Title="MainWindow" Height="350" Width="525">

    <Grid Name="MainGrid" Margin="10">

        <TextBox Name="TextBoxFirstName" Margin="5">

            <TextBox.Text>

                <Binding Path="FirstName" UpdateSourceTrigger="PropertyChanged" >

                    <Binding.ValidationRules>

                        <local:TextBoxNotEmptyValidationRule x:Name="FirstNameValidation" ValidatesOnTargetUpdated="True"

                                                             Message="You must enter a first name."/>

                    </Binding.ValidationRules>

                </Binding>

            </TextBox.Text>

        </TextBox>

        <TextBox Name="TextBoxLastName" Margin="5,20">

            <TextBox.Text>

                <Binding Path="LastName" UpdateSourceTrigger="PropertyChanged" >

                    <Binding.ValidationRules>

                        <local:TextBoxNotEmptyValidationRule x:Name="LastNameValidation" ValidatesOnTargetUpdated="True"

                                                             Message="You must enter a last name."/>

                    </Binding.ValidationRules>

                </Binding>

            </TextBox.Text>

        </TextBox>

        <TextBox Name="TextBoxAge" Grid.Row="2" Grid.Column="1" Margin="5,40">

            <TextBox.Text>

                <Binding Path="Age" UpdateSourceTrigger="PropertyChanged" >

                    <Binding.ValidationRules>

                        <local:OverThirteenValidationRule x:Name="AgeValidation" ValidatesOnTargetUpdated="True"/>

                    </Binding.ValidationRules>

                </Binding>

            </TextBox.Text>

        </TextBox>

        <TextBox Name="TextBoxPhone" Margin="50">

            <TextBox.Text>

                <Binding Path="Phone" UpdateSourceTrigger="PropertyChanged" >

                    <Binding.ValidationRules>

                        <local:TextBoxNotEmptyValidationRule x:Name="PhoneValidation" ValidatesOnTargetUpdated="True"

                                                             Message="You must enter a phone number."/>

                    </Binding.ValidationRules>

                </Binding>

            </TextBox.Text>

        </TextBox>

 <TextBox Name="TextBoxPhone2" Margin="30,40">

            <TextBox.Text>

                <Binding Path="Phone2" UpdateSourceTrigger="PropertyChanged" >

                    <Binding.ValidationRules>

                        <local:TextBoxNotEmptyValidationRule x:Name="PhoneValidation" ValidatesOnTargetUpdated="True"

                                                             Message="You must enter a phone number."/>

                    </Binding.ValidationRules>

                </Binding>

            </TextBox.Text>

        </TextBox>

        <TextBox Name="TextBoxStatus" Margin="30,80">

            <TextBox.Text>

                <Binding Path="Status" UpdateSourceTrigger="PropertyChanged" >

                    <Binding.ValidationRules>

                        <local:TextBoxNotEmptyValidationRule x:Name="Status" ValidatesOnTargetUpdated="True"

                                                             Message="You must enter a phone number."/>

                    </Binding.ValidationRules>

                </Binding>

            </TextBox.Text>

        </TextBox>

        <!-- Validation List -->

        <StackPanel Grid.Row="4" Grid.ColumnSpan="2" Margin="5">

            <StackPanel.Resources>

                <Style TargetType="TextBlock">

                    <Setter Property="Foreground" Value="Red" />

                </Style>

                <local:ErrorCollectionToVisibility x:Key="ToVisibility" />

            </StackPanel.Resources>

            <TextBlock Visibility="{Binding ElementName=TextBoxFirstName, Path=(Validation.Errors), Converter={StaticResource ToVisibility}}">

                <TextBlock.Text>

                    <MultiBinding StringFormat="{}{0} - {1}">

                        <Binding ElementName="labelFirstName" Path="Text"/>

                        <Binding ElementName="TextBoxFirstName" Path="(Validation.Errors)[0].ErrorContent"/>

                    </MultiBinding>

                </TextBlock.Text>

            </TextBlock>

            <TextBlock Visibility="{Binding ElementName=TextBoxLastName, Path=(Validation.Errors), Converter={StaticResource ToVisibility}}">>

                <TextBlock.Text>

                    <MultiBinding StringFormat="LastName - {0}">

                        <Binding ElementName="TextBoxLastName" Path="(Validation.Errors)[0].ErrorContent"/>

                    </MultiBinding>

                </TextBlock.Text>

            </TextBlock>

            <TextBlock Visibility="{Binding ElementName=TextBoxAge, Path=(Validation.Errors), Converter={StaticResource ToVisibility}}">>

                <TextBlock.Text>

                    <MultiBinding StringFormat="Age - {0}">

                        <Binding ElementName="TextBoxAge" Path="(Validation.Errors)[0].ErrorContent"/>

                    </MultiBinding>

                </TextBlock.Text>

            </TextBlock>

            <TextBlock Visibility="{Binding ElementName=TextBoxPhone, Path=(Validation.Errors), Converter={StaticResource ToVisibility}}">>

                <TextBlock.Text>

                    <MultiBinding StringFormat="Phone - {0}">

                        <Binding ElementName="TextBoxPhone" Path="(Validation.Errors)[0].ErrorContent"/>

                    </MultiBinding>

                </TextBlock.Text>

            </TextBlock>

        

        </StackPanel>

        <Button Content="Submit" Padding="10,3,10,3" HorizontalAlignment="Right"

                Name="buttonSubmit" VerticalAlignment="Top">

            <Button.Style>

                <Style TargetType="{x:Type Button}">

                    <Setter Property="IsEnabled" Value="false" />

                    <Style.Triggers>

                        <MultiDataTrigger>

                            <MultiDataTrigger.Conditions>

                            <!--I want to save all the path of text boxes and write something general that will refer to everyone -->

                                <Condition Binding="{Binding ElementName=TextBoxFirstName, Path=(Validation.HasError)}" Value="false" />

                                <Condition Binding="{Binding ElementName=TextBoxLastName, Path=(Validation.HasError)}" Value="false" />

                                <Condition Binding="{Binding ElementName=TextBoxAge, Path=(Validation.HasError)}" Value="false" />

                                <Condition Binding="{Binding ElementName=TextBoxPhone, Path=(Validation.HasError)}" Value="false" />

                                 <Condition Binding="{Binding ElementName=TextBoxPhone2, Path=(Validation.HasError)}" Value="false" />

                            </MultiDataTrigger.Conditions>

                            <Setter Property="IsEnabled" Value="true" />

                        </MultiDataTrigger>

                    </Style.Triggers>

                </Style>

            </Button.Style>

        </Button>

    </Grid>

</Window>
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
5,698
Location
Chesapeake, VA
Programming Experience
10+
Yes. Instead of trying to do the enable/disable logic all through the View in the XAML, do this in the View Model where this business logic really belongs, specifically, in the Command bound to the button. Commands have a CanExecute property.
 

Niso

New member
Joined
Nov 30, 2020
Messages
3
Programming Experience
1-3
It's not so clear to me how to do it with Command,
I will explain myself more clearly.
Every time you leave the focus of the text box and the text is invalid, a corresponding message immediately appears, the thing is that after clicking the button I actually take all the content of the boxes received via binding (with the setting mode=TwoWay) to the object and then perform all kinds of other actions on the same object.
Now suppose I did Command as you said, how do I know how to update CanExecute to false, I don't have a full indication from the object's properties to say unequivocally if there is an incorrect value (from the same text box with the wrong content), let's say if the object's properties are of type double /int for which the Binding will not be performed if we enter a value of type string and the default will remain 0 so this value is normal and therefore I have no information telling me that a certain field is problematic!
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
5,698
Location
Chesapeake, VA
Programming Experience
10+
This may help a little bit to show how that communication can happen:
 
Top Bottom