How to call CanExecute when validation cancels UpdateSourceTrigger - c#

I am using a ValidationRule on a TextBox in my View, and that ValidationRule is working properly.
However, a problem arises when I am in the state where the canExecute method for a Command (on a Button in this case) has returned true (Button is enabled), and then the user changes the contents of the TextBox so the ValidationRule returns a false ValidationResult. This results in the ViewModel property bound to the Button.Text not being updated, which means the canExecute method still thinks results are good and returns true.
So - how can I get the ViewModel property in question to update in spite of the false ValidationResult? Or is there another way of doing all this?
Edit:Here is the XAML for my TextBox:
<TextBox HorizontalAlignment="Left" Margin="67,50,0,0" VerticalAlignment="Top" Width="27">
<TextBox.Text>
<Binding Path="MachineNo" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MachineNoValidate/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

After doing some more research, the solution appears to be implementing the IDataErrorInfo interface on my ViewModel. I then have full access to the current contents of the TextBox through the bound property.
Here is the new XAML:
<TextBox HorizontalAlignment="Left" Margin="67,50,0,0" VerticalAlignment="Top" Width="27"
Text="{Binding MachineNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}"/>
Only this[] needs to be implemented; WPF does not use the Error property.

Related

Run WPF Validation only if control is Visible (Disable validation if control is Collapsed)

I want to make WPF validations run only if the control that is being validated is Visible.
In my project, depending on the user's choice, some controls are Collapsed.
I have a button that is enabled only if there are no validation errors (I use WPF MultiValue Converter and check if all controls are valid - HasError is false for all controls).
Validations are implemented using ValidationRules.
So, my goal is to validate all currently Visible controls (Only Visible!), instead of Button being disabled because collapsed fields are empty...
Is there a way to make Validation Error raise only when control is Visible and input is Invalid?
I have searched on the internet for a few days, but I haven't found any solutions for this situation...
Thanks in advance! Best regards!
If you use xaml for setting your rules the code below do what yuo want. Trigger for visibility, no binding - no validation) I used TextBox only as example.
Also you can use other approach, pass to your ValidationRule your property which shows that elements are hidden, and check it inside rules How to bind values from xaml to validation rule?
<TextBox Visibility="{Binding IsVisible, Converter={wpfApp1:BoolToVisibilityConverter}}">
<TextBox.Text>
<Binding Path="Text" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<wpfApp1:TextValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Visibility" Value="Collapsed">
<Setter Property="Text" Value="{x:Null}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
You can add property to your validation rule like Enabled and use it while validating (return successfull validation if not enabled).
Then bind that property in XAML to either Visibility property of the control or whatever determines if control is visible (ie. CheckBox's IsChecked property).
Edit: Code for clarity:
<CheckBox Name="chkName" />
<TextBox Visibility="{Binding IsChecked, ElementName=chkName, Convertor...}">
<TextBox.Text>
<Binding Path="ModelProperty">
<Binding.ValidationRules>
<wpfApp1:TextValidationRule Enabled="{Binding IsChecked, ElementName=chkName}" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

Force RadioButtons to only change if the bound value actually changes

I have a bit of a strange case. The issue is that I have 3 radiobuttons and they are binded to the EffectiveValue property of my viewmodel.
<StackPanel Grid.Column="2" Orientation="Horizontal" Margin="5,0,0,0">
<StackPanel.Visibility>
<MultiBinding Converter="{StaticResource MultiBoolToVisibilityHidden}">
<Binding Path="IsSelected" RelativeSource="{RelativeSource AncestorType=telerik:RadListBoxItem}"/>
<Binding Path="Criterion.IsOverridable"/>
<Binding Path="DataContext.CanOverrideEvaluation" ElementName="ThisInformationControl"/>
</MultiBinding>
</StackPanel.Visibility>
<telerik:RadRadioButton Content="Y" IsChecked="{Binding EffectiveValue, Converter={StaticResource EnumToBool}, ConverterParameter={x:Static utilities:Ternary.TRUE}, Mode=OneWay}" Style="{StaticResource EmptyRadioButtonStyle}"
Command="{Binding OverrideValueCommand}" CommandParameter="{x:Static utilities:Ternary.TRUE}" Margin="2,1" Width="16" VerticalAlignment="Center"/>
<telerik:RadRadioButton Content="?" IsChecked="{Binding EffectiveValue, Converter={StaticResource EnumToBool}, ConverterParameter={x:Static utilities:Ternary.UNKNOWN}, Mode=OneWay}" Style="{StaticResource EmptyRadioButtonStyle}"
Command="{Binding OverrideValueCommand}" CommandParameter="{x:Static utilities:Ternary.UNKNOWN}" Margin="2,1" Width="16" VerticalAlignment="Center"/>
<telerik:RadRadioButton Content="N" IsChecked="{Binding EffectiveValue, Converter={StaticResource EnumToBool}, ConverterParameter={x:Static utilities:Ternary.FALSE}, Mode=OneWay}" Style="{StaticResource EmptyRadioButtonStyle}"
Command="{Binding OverrideValueCommand}" CommandParameter="{x:Static utilities:Ternary.FALSE}" Margin="2,1" Width="16" VerticalAlignment="Center"/>
</StackPanel>
The problem is this. Say my ViewModel Effective Value is 'Y'. I click the 'N' button. But then based on certain conditions, I do not actually set the EffectiveValue to 'N' and it remains 'Y'. The problem I am having is now the 'N' looks selected even though the viewmodel still says that the value is 'Y'. What can I do to make sure my radiobuttons strictly listen to the viewmodel's value?
My current workaround it to force a property changed on the effective value but I feel this is kind of a hack.
Thanks
I think the answer lies with your radio button bindings. Notice that you have them set to OneWay, but you said that based on certain conditions you keep the value as 'Y'. How does the WPF control know that you've rejected the UI change?
I suggest changing the binding Mode to TwoWay and maybe also include UpdateSourceTrigger=PropertyChanged in the bindings. Then your code behind and the UI can communicate "two ways" to each other about what the appropriate state of the radio button should be.

How to use EventToCommand - Error in XAML

The user input something in the TextBox and hits the Enter-button. When the Enter-button is hit the AddFieldCommand is called. How do I do what in XAML?
My code is giving me a warning: "The Property 'Text' is set more than once".
I need to know which object in the Canvas that is being updated, so I can add the content from the TextBox to my model - this is why I use EventToCommand.
<TextBox x:Name="txtFields" Text="{Binding FieldsTextProperty, UpdateSourceTrigger=PropertyChanged}" Height="23" TextWrapping="NoWrap" Background="#FFCBEECD" AcceptsReturn="False" >
<TextBox.InputBindings>
<KeyBinding Key="Enter" >
</KeyBinding>
</TextBox.InputBindings>
<i:EventTrigger EventName="AddField">
<cmd:EventToCommand Command="{Binding DataContext.AddFieldCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</TextBox>
Can anybody help?
In XAML, everything that’s placed inside an element becomes its content. For text boxes, this sets the Text property. This is to allow things like this:
<TextBox>Foo bar</TextBox>
So you can place the content within the XAML elements. This is equivalent to this:
<TextBox Text="Foo bar" />
Now, if you look at your XAML code, you will notice that you have two elements inside the TextBox element: TextBox.InputBindings and i:EventTrigger. To explain the first, you need to know that there is another way to specify an element’s property values, by using child elements. This makes the above examples equivalent to this:
<TextBox>
<TextBox.Text>Foo bar</TextBox.Text>
</TextBox>
This works for all properties of TextBox. Now, InputBindings is an property of TextBox, so having it as a child element will correctly set the property and it will also not affect the element’s content value (so Text isn’t set by its presence). However, i:EventTrigger is not an property of TextBox, so this will set the content of the TextBox—giving the error message you see.
To use interaction event triggers, you need to place these into the attached property i:Interaction.Triggers. As an attached property, it can be set with a child element like above. So, your code should look like this:
<TextBox …>
<i:Interaction.Triggers>
<i:EventTrigger EventName="AddField">
<cmd:EventToCommand … />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
You can use ICommand interface to execute your command and use IsDefault=true property of the button which allows it to remain focus.So when you click enter it will execute the Command you binded on the button.
<TextBox x:Name="txtFields" Text="{Binding FieldsTextProperty,UpdateSourceTrigger=PropertyChanged}" Height="23" TextWrapping="NoWrap" Background="#FFCBEECD" AcceptsReturn="False" />
<Button Name="btnEnter" IsDefault="True" Command="{Binding DataContext.AddFieldCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />

Add brackets to text box value

I want to know if there is option that when I type into a text box or drag to anything (I'm using D&D functionality), the text on it will automatically insert brackets. I don't want to do that on the logic or in the code beyond just in the ui. Is that posible?
For example: if I type AAA, I will see in the text box (AAA).
I dont want to do that on the logic or in the code beyond
By your conditions it is not possible. Something has to capture the change event and add the brackets to the text. That something is not possible without logic as found in code behind.
The options are
Subscribe to the textblock's SelectionChange event and add the brackets.
Create a custom control which does #1 internal so the consumer doesn't have to do it. (By a technicality it answer's your question).
Put the textblock control between two labels which have the brackets as their context. Bind their visibility to a Boolean on the VM which reports when the bound data of the textblock has changed. If there is text then they become visible, if there is no text it is hidden. Downside is that this is not caught as the user types or until it fully changed, only when exiting the control.
Here is #3
<Label Content="(" Visibility="{Binding HasText, Converter={StaticResource WindowsVisibilityBooleanConverter}}" />
<TextBox Text="{Binding TextInput}"
Height="18"
HorizontalAlignment="Stretch" />
<Label Content=")" Visibility="{Binding HasText, Converter={StaticResource WindowsVisibilityBooleanConverter}}" />
Without any of your own logic code, I suppose this is the closest thing to what you want.
<TextBox x:Name="tbInput" />
<TextBlock Text="{Binding ElementName='tbInput', Path=Text, StringFormat={}({0})}" />
The downside would be that you'll always see the empty brackets () if the TextBox is empty.
See: String format using MultiBinding?
<StackPanel>
<Slider x:Name="sl1" Minimum="10" Maximum="100"/>
<Slider x:Name="sl2" Minimum="10" Maximum="100"/>
<Label x:Name="label13" Background="Yellow" Foreground="Black">
<Label.Content>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} x {1} Test">
<Binding ElementName="sl1" Path="Value" />
<Binding ElementName="sl2" Path="Value" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Label.Content>
</Label>
</StackPanel>

WPF - Workaround for ValidationRule not being a DependencyObject

What is the best solution for not being able to use data binding on a ValidationRule property since ValiationRule is not a DependencyObject?
Below is an example of what I would like to do. I want to be able to validate the text in the TextBox against some other DependencyProperty.
<TextBox Name="myTextBox">
<TextBox.Text>
<Binding Path="MySource" UpdateSourceTrigger="PropertyChanged">
<base:EqualsRule Target="{Binding MyTarget}" />
</Binding>
</TextBox.Text>
</TextBox>
You could use Josh Smith's virtual branch approach.

Categories