WPF Error Validation doesn't show ErrorTemplate - wpf

I have a window like
<Window.Resources>
<ControlTemplate x:Key="ValidationTemplate">
<DockPanel>
<TextBlock Foreground="Red" FontSize="20">!</TextBlock>
<AdornedElementPlaceholder/>
</DockPanel>
</ControlTemplate>
<Style x:Key="TextBoxInError" 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>
</Style>
</Window.Resources>
<TextBox x:Name="SupportFolder"
Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
Style="{StaticResource TextBoxInError}"
Padding="2">
<TextBox.Text>
<Binding Path="Preferences.SupportFolder" Mode="TwoWay" UpdateSourceTrigger="LostFocus">
<Binding.ValidationRules>
<local:FolderExistsValidationRule ValidationStep="RawProposedValue"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
So my impression is that when the input for the TextBox is in error that there will be a small red exclamation mark to the left of the TextBox and because of the Style triggers there will be a ToolTip displaying the error. The ToolTip works but I don't see the exclamation point indicating the error. I took this code from the Microsoft Samples but I cannot for the life of me see where I have made a mistake. The sample works (Data Binding -> BindingValidation) but I cannot seem to reproduce the code. Would someone act as a second pair of eyes and see what I am doing wrong?

You should dock the TextBlock in the error template to the left or right:
<TextBlock Foreground="Red" FontSize="20" DockPanel.Dock="Right">!</TextBlock>
Using your current markup, the TextBlock will end up "under" the adorned element.

Related

Bind header textblock isEnabled to parent Groupbox isEnabled

Referencing to this question: WPF Databinding: How do I access the "parent" data context?
I wanna do something similiar, but for the header of a Groupbox (because the header does not concern with the Box is being disabled and thus is always black while the rest is light gray. This looks a bit strange to me if all the content of the box is gray, the above is gray, but the box title itself stays black.
So I tried to use the approach mentioned in the linked question by flq to simply bind the isEnabled property of the header textblock to the isEnabled property of the groupbox but it seems that my binding at some point fails and I don't know where and why exactly.
heres my current code:
<GroupBox Header="Change Steps" Grid.Row="2" Grid.ColumnSpan="3" Name="gbChangeSteps">
<GroupBox.Style>
<Style TargetType="GroupBox">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}" FontWeight="Bold" Height="19" Foreground="Black" IsEnabled="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GroupBox}}, Path=isEnabled}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupBox.Style>
<!-- ... (some non relevant Content)-->
</GroupBox>
after additional research I found the post Disable groupBox including the groupBox name in WPF
that lead me, in combination with Properties->Create Databinding->Binding type->UIElement to the solution that fixed both problems, the one this question was about and the original one that lead to entire restyling, which was that letters like the small g got messed up in the header.
This is the code that fixed the issue:
<GroupBox.Style>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}" FontWeight="Bold" Height="19" IsEnabled="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UIElement}}}">
<TextBlock.Style>
<Style>
<Style.Triggers>
<Trigger Property="Control.IsEnabled" Value="False">
<Setter Property="Control.Foreground" Value ="#FF6D6D6D" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupBox.Style>

How can I binding a listboxitem content in a muiltbinding?

I am doing my first project using wpf. I really need your help and suggestion. Thanks in advance.
I am building a screen, which has two listboxes A & B. Listbox A is binding to items load from database. listbox B is binding to a statics list. When user selects an item in listbox A, the associate item will be highlighted in listbox B. I am doing it by using MultiBinding in a listboxtitem. I'd like to pass selected data object and listboxitem content. The Convert() will take these two variables and check them. If match, it will return true to IsSelected property of item and highlight it. But it seems item content (statics string) can't be passed to converter(). What should I do?
see my xaml code:
<ListBox Name="AbsenseCode" ItemsSource="{Binding absenseCodeItems}" Grid.Row="1" Grid.Column="1" Grid.RowSpan="5" Margin="20,0,20,5" >
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected">
<Setter.Value>
<MultiBinding Converter="{StaticResource IsItemSelected}">
<Binding ElementName="FilterListbox" Path="SelectedItem"/>
<Binding Path="Content"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
when debugging, the second binging variable, content of item, is "{DependencyProperty.UnsetValue}".
this is a few months old, but I had a similar situation.
First, build a iMultiValueConveter that will compare two values and return the result to a string. "true" or "false" or "yes" or "no".
then in the XAML, define a style that can be triggered by the converter return. In this, ListBoxB has an ellipse where the fill will be green if the values match, red if they dont:
<Window.Resources>
<myNamespace:IsEqualConverter x:Key="IsEqualConverter" />
</Window.Resources>
<ListBox Name="ListBoxA" ItemsSource="{Binding}">
</ListBox>
<ListBox Name="ListBoxB" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<StackPanel>
<StackPanel.Resources>
<!-- style triggered by converter result -->
<Style TargetType="Ellipse" x:Key="EllipseStyle">
<Setter Property="Fill" Value="#E5E5E5" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=result,Path=Text}" Value="true">
<Setter Property="Fill" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=result,Path=Text}" Value="false">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<Ellipse Height="50" Width="50" Style="{StaticResoure EllipseStyle}" />
<TextBlock x:Name="value0" Text="{Binding ElementName=ListBoxA,Path=SelectedItem.(Whatever),Mode=OneWay}" />
<TextBlock x:Name="value1" Text="{Data Binding you want to compare to}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock x:Name="result">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource IsEqualConverter}">
<Binding ElementName="value0" Path="Text" />
<Binding ElementName="value1" Path="Text" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</ListBox.ItemTemplate>
</ListBox>

DataTriggers : How it works

I want to implement a DataTrigger for say, textBox1. When Text inside textBox1 is "ABC" then I want to display "Data matched!" in another TextBox say, textBox2. I have written below xaml code for this but its not working. I am getting below error message.
'Text' member is not valid because it does not have a qualifying type name
XAML code for this is:
<Window x:Class="ControlTemplateDemo.Animation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="Animation" Height="300" Width="607">
<Grid>
<Border Background="White">
<StackPanel Margin="30" HorizontalAlignment="Left" Width="500" Height="209">
<TextBox Name="textBox1">
<TextBox.Triggers>
<DataTrigger Binding="{Binding Path=Text}">
<DataTrigger.Value>
<sys:String>ABC</sys:String>
</DataTrigger.Value>
<Setter TargetName="textBox2" Property="Text" Value="Data matched!"/>
</DataTrigger>
</TextBox.Triggers>
</TextBox>
<TextBox Name="textBox2">
</TextBox>
</StackPanel>
</Border>
</Grid>
</Window>
Is there any problem in binding?
Thanks,
Hemant
You need to give the DataTrigger in a Style for the second TextBox
something like:
<StackPanel>
<TextBox x:Name="inputBox" />
<TextBox Margin="0 25 0 0">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Text"
Value="No Match Found" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=inputBox,
Path=Text}"
Value="ABC">
<Setter Property="Text"
Value="Match Found" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
TextBox.Triggers does not support DataTrigger. I'd guess it's only for EventTriggers as the documentation states
on a side-note, I normally have my bindings in the element that ends up as the target(as much as I can). This way I find it easier to debug at-least personally. If the TextBox has wrong info I instantly check it's binding than every binding in my xaml file to see which element has a wrong binding that ends up updating my TextBox.

Binding the background colour of a control using a trigger in WPF/XAML

Okay, first off I have no experience of WPF whatsoever so please bear with me and apologies if my terminology is a little wayward... ;)
The following code snippet is part of a WPF application that I have inherited. The trigger governs whether mandatory fields on a particular form are highlighted or not. The code works but the highlighting seems to apply to the control and the border (??) which contains it.
<ItemsControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="clr-namespace:Caliburn.PresentationFramework.ApplicationModel;assembly=Caliburn.PresentationFramework"
x:Class="company.product.Jobs.JobParametersEditor"
IsTabStop="False">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel MinHeight="30">
<TextBlock Text="{Binding DisplayName, Mode=OneWay}"
DockPanel.Dock="Left"
VerticalAlignment="Center"
MinWidth="120"
Margin="6,0" />
<Border>
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Background"
Value="{x:Null}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsValid}"
Value="False">
<Setter Property="Background"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<ContentControl cal:View.Model="{Binding ValueEditor}"
ToolTip="{Binding ToolTip}"
IsTabStop="False"
MinHeight="19"
VerticalAlignment="Center"
HorizontalAlignment="Stretch" />
</Border>
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The result is a bit clunky so I would like to restrict the highlighting to the control only but I can't figure out how to do it. I've tried moving the trigger so that it applies to the ContentControl instead of the Border but that didn't work and fiddling about with border margins, padding and thickness hasn't had any effect either.
Could anybody enlighten me as to how to accomplish this?

WPF TextBox setting Text using Trigger during validation

I am having a requirement where in I have to revert the values of a TextBox to old value when the user enters a wrong input. I am using MVVM framework so I dont want to write any codebehind. The Text and Tag of TextBox is databound from ViewModel variable. So my Tag field of TextBox will always have old value. I want to use the Tag field value to revert my Text value.
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right"
Foreground="Orange"
FontSize="12pt">
</TextBlock>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true" >
<Setter Property="ToolTip"
Value="{Binding Path=Tag,RelativeSource={RelativeSource Self}}">
</Setter>
<Setter Property="Text"
Value="{Binding Path=Tag,RelativeSource={RelativeSource Self}}">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<TextBox Width="68" Tag="{Binding SampleText}" Height="23" HorizontalAlignment="Left" Margin="39,37,0,0" VerticalAlignment="Top" >
<TextBox.Text>
<Binding Path="SampleText" NotifyOnValidationError="True" ValidatesOnDataErrors="True" ValidatesOnExceptions="True">
<Binding.ValidationRules>
<val:SampleTextValidator></val:SampleTextValidator>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Now When an error happens, the TextBox is highlighted red.I have written a Trigger to revert the value back to original value (value stored in Tag field). Tt is not working. But Tooltip part is working. I am confused fully. Please help where am I doing wrong!!!. Correct me with a sample code if possible!!!!
My first guess is that when you made your text input invalid (eg. delete all values), you cause the tag to bind to the same value, hence, it will reflect an empty string.
What you need is a separate property for your original value to bind your tag to.
private string _oldValue;
public string OldValue
{
get {...}
set {... NotifyPropertyChanged()...}
}
private string _sampleText;
public string SampleText
{
get { return _sampleText; }
set {
OldValue = _sampleText;
_sampleText = value;
NotifyPropertyChanged(...);
}
}
<TextBox Width="68" Tag="{Binding OldValue}" ... >
Don't forget to implement INotifyPropertyChanged.

Resources