Binding to last Validation Error - wpf

I have a style trigger for create a tooltip with a validation error:
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel>
<Border BorderBrush="Red" BorderThickness="2" CornerRadius="2" Background="{x:Null}">
<AdornedElementPlaceholder/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
I'm displaying first error (Validation.Errors)[0].ErrorContent), but I want to display the last one (the last is more prioritary, Framework textbox adds its validation errors at the end, for example strings not representing a date).
Thanks.

Well, for one thing you could change the Path to all errors and add a ValueConverter that returns only the last message.
A lot of people also move validation completely to the view-model and ditch the validation rules, that way you have a lot of control over what exactly you expose to the view.

Related

Styling a combobox's PART_EditableTextBox

I want to add conditionnal formatting (just font color) to the textbox part of a combobox. According to MSDN, it's the "PART_EditableTextBox" element. A quick search on SO got me started but I now face a problem: it overrides the whole template. According to this SO answer, I can use "BasedOn" to override only specific properties but I've no idea how/where to use it.
This is my current template:
<ControlTemplate x:Key="MyComboBoxTextBox" TargetType="ComboBox" <!--Here?--> >
<TextBox x:Name="PART_EditableTextBox" <!--Maybe Here?-->>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Text" Value="MAL">
<Setter Property="Foreground" Value="DarkOrange"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</ControlTemplate>
It works, I can still type in valid values and "MAL" does make the text orange but there's no dropdown anymore.
On MSDN, I found the following:
<TextBox x:Name="PART_EditableTextBox"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Margin="3,3,23,3"
Focusable="True"
Background="Transparent"
Visibility="Hidden"
IsReadOnly="{TemplateBinding IsReadOnly}" />
I suppose I should base my template on this "ComboBoxTextBox" but I don't know how to reference it. Do I really need to copy the whole template or is there a way to override a specific property?
EDIT:
On the same MSDN page comboboxTextBox is defined as
<ControlTemplate x:Key="ComboBoxTextBox"
TargetType="{x:Type TextBox}">
<Border x:Name="PART_ContentHost"
Focusable="False"
Background="{TemplateBinding Background}" />
</ControlTemplate>
I don't see how overriding this template removes the dropdown list.
Ok I think I got really confused after reading all of your code and having a really looooooong day at work, I totally missed the point of your question.... which is
I want to add conditionnal formatting (just font color) to the textbox part of a combobox
Well if that's all you want to do, then it's really easy with just a simple style trigger.
I can achieve that with this xaml.
<ComboBox HorizontalAlignment="Center" VerticalAlignment="Center">
<ComboBox.Resources>
<Style TargetType="ComboBox">
<Style.Triggers>
<Trigger Property="Text" Value="MAL">
<Setter Property="Foreground" Value="DarkOrange" />
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Resources>
<ComboBoxItem>MAL</ComboBoxItem>
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
<ComboBoxItem>3</ComboBoxItem>
</ComboBox>
Hope this helps!

WPF ControlTemplate Height

I have the following style for validating input in my controls:
<Style x:Key="MyErrorTemplate" TargetType="Control">
<Style.Setters>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate x:Name="ControlErrorTemplate">
<StackPanel Orientation="Vertical" Height="Auto">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Red" FontSize="20">!</TextBlock>
<AdornedElementPlaceholder x:Name="Holder"/>
</StackPanel>
<Label Foreground="Red" Content="{Binding ElementName=Holder,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
If an error happens, the error message in the label appears under the control (e.g. textbox) and overlaps the control below. I made StackPanel's Height="Auto", but it didn't help. Each control is in a Grid cell, and the Grid's row Height is also Auto.
Could you please tell me what I am missing? I want the error message to push what is below down.
Thanks.
Validation.ErrorTemplate shows error feedback on an adorner layer. This means all controls in this template will not be considered when the layout system is measuring and arranging the controls on the adorned element layer.
I found this and thanks LPL, i did not know that about the adorner layer.
My solution was a margin "hack". I just used the trigger:
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="Margin" Value="0,0,0,28"/>
</Trigger>
</Style.Triggers>
To increase the bottom margin of the adorned textbox. I set the margin large enough to make room for a single string textblock/label and then the content below was moved down

WPF Style Validation Trigger Command

I have some dynamic generated Textboxes with Validators. I want them to send a Command to VM, if a validation error occurs. This Behavior is placed in a style, so I don't need to write it into the xaml generation.
Here's the Code:
<behaviors:Triggers x:Key="validationTrigger" x:Shared="False">
<behaviors:ValidationErrorEventTrigger>
<cmd:EventToCommand Command="{Binding ValidationError,NotifyOnValidationError=True}"
PassEventArgsToCommand="True" />
</behaviors:ValidationErrorEventTrigger>
</behaviors:Triggers>
<Style x:Key="EditableTextBox" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#DDFFDD" />
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="Red" BorderThickness="2">
<AdornedElementPlaceholder />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="behaviors:OCCInteraction.Triggers" Value="{StaticResource ResourceKey=validationTrigger}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Background" Value="#FFDDDD"/>
</Trigger>
</Style.Triggers>
</Style>
The Problem I'm having now, is that the "Onvalidation" Event is called in the VlidationErrorEventTrigger class, but the Command isn't called in the Viewmodel.
I've tested it with a direct integration and not with a style and it works this way.
So maybe it has something to do with the Binding of the Command or so...
I hope this description is enough to solve the Problem. If not please tell me :)
I am not sure how you binding is done but assuming that DataContext of you `Control/Window has your ViewModel Instance andValidationError` is your command...
<behaviors:Triggers x:Key="validationTrigger" x:Shared="False">
<behaviors:ValidationErrorEventTrigger>
<cmd:EventToCommand Command="{Binding Path=DataContext.ValidationError,RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}",NotifyOnValidationError=True}"
PassEventArgsToCommand="True" />
</behaviors:ValidationErrorEventTrigger>
</behaviors:Triggers>
This is assuming that your trigger is not able to find the command required.

wpf DataGrid.RowValidationErrorTemplate - how to actually change row appearance instead of header row?

I'm currently using row validation for my datagrid. I'm trying to change the appearance of a row when it is not valid. My code so far in terms of visually reporting the error:
<DataGrid.RowValidationErrorTemplate>
<ControlTemplate>
<Grid Margin="0,-2,0,-2" Background="Red" HorizontalAlignment="Stretch"
ToolTip="{Binding RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type DataGridRow}},
Path=(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" FontSize="{TemplateBinding FontSize}"
FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</DataGrid.RowValidationErrorTemplate>
It seems that this will only affect my header row. Is there a way I can handle this RowValidationErrorTemplate to modify the row appearance? I would like to make the entire row's background red or anything like that.
Any ideas?
Please let me know if I need to provide more code for this particular problem.
Thanks in advance!
you can update the style of DataGridRow type and try to set error background based on Validation flag against the row.
Something like this...
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}"
BasedOn="{StaticResource (x:Type DataGridRow)}"> <!--BasedOn is optional-->
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
Let me know if this helps.

WPF Expander still shows Validation Error adorner when shrunk

I've got a style for a TextBox to show a validation error message as follows:
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<Border BorderBrush="{Binding Path=ErrorContent,
Converter={StaticResource ValidationErrorToBrushConverter}}" BorderThickness="2">
<AdornedElementPlaceholder />
</Border>
<Image Name="image1" Height="14" Width="14" Stretch="Fill" Margin="1,1,1,1"
Source="{Binding Path=ErrorContent,
Converter={StaticResource ValidationErrorToImageSourceConverter}}"
ToolTip="{Binding Path=ErrorContent}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The TextBox lives in an Expander. When I open the Expander, the TextBox allows for input, but will fail validation if the input is NullorEmpty, or contains special characters.
My problem is that when I trigger a validation error, the TextBox lights up in red and shows an icon with the message as a tooltip. All good so far. BUT when i close the Expander without passing validation, the red outline and icon with tooltip are still there! Even with the Expander shrunk down! Just floating there... This is not good behavior.
Any ideas on how to get the Validation stuff to hide along with all the other controls in the Expander? Also, the Style for validation is declared in the resources of the UserControl, not in the Expander itself.
I ended up simply clearing the TextBox upon closing the Expander. That way, the validation error goes away and the box is clear and ready for another input when the Expander is opened back up.
I had the same problem. I fixed it by putting an AdornerDecorator as the first child object of the expander. The AdornerDecorator is collapsed when the Expander is collapsed, so the Adorners should all disappear too.
I've resolved this same problem by setting the Validation.ErrorTemplate property to null when the TextBox is hidden
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsHitTestVisible" Value="False">
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
</Trigger>
</Style.Triggers>
</Style>

Resources