DataTriggers : How it works - wpf

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.

Related

Workaround for caret textbox with binding an property changed XAML

I have a lot of textboxes binded in twoway mode ot a different properties with UpdateSourceTrigger=PropertyChanged and I have one annoying problem: when I enter or delete a value - caret moves to the begin of the string.
I found a solution here:
TextBox with CurrencyFormat and PropertyChanged trigger doesn't accept text right
but I cannot implement it correctly. I probably miss something.
Here is my XAMLbinding for one of textboxes:
enter code here <TextBox x:Name="TextBoxFirstPersonCameraMinPosY" Width="150" VerticalAlignment="Center" FontWeight="Normal"
Text="{Binding Path=CameraLimitationParameters.FirstPersonCameraPosition.MinValue.Y, Mode=TwoWay, IsAsync=True, Delay=0, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ToStringConverter}}" Style="{StaticResource {x:Type TextBox}}"
MaxLength="40" Margin="10,0,0,0" MinWidth="150" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled" MaxWidth="150"></TextBox>
and here is my style:
enter code here<Page.Resources >
<ObjectDataProvider x:Key="CameraMode"
MethodName="GetValues" ObjectType="{x:Type sys:Enum}" >
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="settingsManager:CameraBehavior"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<settingsManager:ToStringConverter x:Key="ToStringConverter"></settingsManager:ToStringConverter>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="Text" Value="{Binding UpdateSourceTrigger=PropertyChanged}"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Page.Resources>
What did I miss an how to apply this style for all textboxes independently of binding property without duplicating code?
And will this workaround work for my case? Help me please.
Problem was because I set IsAsync=True in TextBox. In this case Async need to be set to false.

TextBox with CurrencyFormat and PropertyChanged trigger doesn't accept text right

I have a TextBox in a WPF window bound to a dependency property of the window of type double (see below). Whenever the user types in the TextBox when
The TextBox is empty, or
All of the text is selected,
the typed text is accepted incorrectly. For example: If I type a '5' in either of these scenarios, the resulting text is "$5.00", but the caret is located before the '5', after the '$'. If I try to type "52.1", I get "$2.15.00".
<Window x:Class="WPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="154" Width="240" Name="ThisWindow"
Background="{StaticResource {x:Static SystemColors.AppWorkspaceBrushKey}}">
<Grid>
<TextBox Text="{Binding ElementName=ThisWindow,
Path=Amount,
StringFormat={}{0:c},
UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
MinWidth="100" />
</Grid>
</Window>
If I remove the UpdateSourceTrigger attribute, it types correctly, but doesn't maintain the currency format.
Any ideas?
This is caused by it trying to apply the formatting after every character press.
As an alternative, I usually just style the TextBox so it only applies formatting when it's not being edited
<Style TargetType="{x:Type TextBox}">
<Setter Property="Text" Value="{Binding SomeValue, StringFormat=C}" />
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="Text" Value="{Binding SomeValue, UpdateSourceTrigger=PropertyChanged}" />
</Trigger>
</Style.Triggers>
</Style>

XAML trigger template to set visibilty based on another element

I have several StackPanels that change visibility based on ToggleButtons. The code below works if I replace Tag with btn1 on the DataTrigger-lines.
How do I use the value of the Tag property?
<Window x:Class="MyTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestApp">
<Window.Resources>
<Style x:Key="panelStyle" TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Tag, Path=IsChecked}" Value="False">
<Setter Property="StackPanel.Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Tag, Path=IsChecked}" Value="True">
<Setter Property="StackPanel.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<WrapPanel>
<ToggleButton Content="One" Name="btn1" />
<ToggleButton Content="Two" Name="btn2" />
<StackPanel Style="{StaticResource panelStyle}" Tag="{Binding btn1}">
<Label Content="Data to panel 1" />
</StackPanel>
<StackPanel Style="{StaticResource panelStyle}" Tag="{Binding btn2}">
<Label Content="Data to panel 2" />
</StackPanel>
</WrapPanel>
</Window>
This question is very similar, but I'm missing details on how to pass an element name.
XAML - Generic textbox stylewith triggers / parameters?
Your bindings are incorrect.
In your DataTemplate the bindings should be:
<DataTrigger Binding="{Binding Path=Tag.IsChecked, RelativeSource={RelativeSource Self}}" Value="False">
<Setter Property="StackPanel.Visibility" Value="Collapsed" />
</DataTrigger>
Here the RelativeSource with a mode of Self tells the binding engine that the object to bind against is object to which the style is being applied (e.g. your StackPanel). The PropertyPath of Tag.IsChecked tells the binding engine to look for a property called IsChecked from the object stored in Tag.
Finally the bindings in your StackPanel should be:
<StackPanel Style="{StaticResource panelStyle}" Tag="{Binding ElementName=btn1}">
<Label Content="Data to panel 1" />
</StackPanel>
Here ElementName creates a binding to another element in the logical tree. If you do not explicitly assign to any properties in a Binding as in your original example:
Tag="{Binding btn1}"
The value specified is assigned to the Path property. So this would be the same as:
Tag="{Binding Path=btn1}"
Also note, that using Tag is not considered best practice since it's type is of object and its use is unrestricted, and hence can take on any number of different meanings throughout your project (which often makes it difficult to understand, especially when used in Templates that are located far away from their actual use).
Hope this helps!
Use Converter: set the visibility of StackPanel:
<StackPanel Visivility="{Binding IsChecked, ElementName=btn1, Converter={StaticResource BooleanToVisibilityConverter}}">
...
</StackPanel>

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?

Accessing ListBox DisplayMemberPath data value in SelectedItem template

I am attempting to create a generic ListBox control to customize edit in place as well as other features.
In the example below, I want to bind the "Text" property of the ListBox "selected item" to the data value of the DisplayMemberPath in the viewed structure. Such XAML binding expression would replace the question marks in the code (Text="{Binding ????????????????").
Using a ContentPresenter instead of binding the text works for display purposes, but I have not been able to bind to the Text component used on the presenter. An alternative to finding the binding expression is to be able to get the Text content from the ContentPresenter.
I can think of a number of ways to accomplish this through code behind, but I am looking for a XAML solution if such thing exists.
I appreciate any ideas. I am almost sure there is a trivial answer to this, but after spending a couple days on it, I admit a nudge in the right direction would greatly help me.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<XmlDataProvider x:Key="NobelLaureatesInPhysics"
XPath="/NobelLaureatesInPhysics">
<x:XData>
<NobelLaureatesInPhysics xmlns="">
<NobelLaureate>
<ID>1</ID>
<Name>Wilhelm Röntgen</Name>
<AwardDate>12/10/1901</AwardDate>
</NobelLaureate>
<NobelLaureate>
<ID>2</ID>
<Name>Hendrik Lorentz</Name>
<AwardDate>12/10/1902</AwardDate>
</NobelLaureate>
<NobelLaureate>
<ID>3</ID>
<Name>Pieter Zeeman</Name>
<AwardDate>12/10/1902</AwardDate>
</NobelLaureate>
</NobelLaureatesInPhysics>
</x:XData>
</XmlDataProvider>
<ControlTemplate x:Key="ItemTemplate"
TargetType="ListBoxItem">
<TextBlock Foreground="Black">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
<ControlTemplate x:Key="SelectedItemTemplate"
TargetType="ListBoxItem">
<TextBox Background="Black"
Foreground="White"
Text="{Binding ????????????????"/>
</ControlTemplate>
<Style TargetType="{x:Type ListBoxItem}"
x:Key="ContainerStyle">
<Setter Property="Template"
Value="{StaticResource ItemTemplate}" />
<Style.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Template"
Value="{StaticResource SelectedItemTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="TestListBoxStyle"
TargetType="{x:Type ListBox}">
<Setter Property="ItemContainerStyle"
Value="{DynamicResource ContainerStyle}" />
</Style>
</Window.Resources>
<Grid>
<ListBox Style="{DynamicResource TestListBoxStyle}"
ItemsSource="{Binding Source={StaticResource NobelLaureatesInPhysics}, XPath=NobelLaureate}"
DisplayMemberPath="Name"/>
</Grid>
{Binding Path=DisplayMemberPath, RelativeSource={RelativeSource Mode=FindAncestor, Type={x:Type ListBox}}
That should work

Resources