Datatrigger on textbox not working - wpf

Hi i am trying to write a datatrigger in which i have to clear a textbox content on checkbox checked.My Code is given below
It works as long as you dont type anything in the textbox.As soon as i type in the textbox the datatrigger fails to work.How can i solve this
<Window x:Class="CheckboxTextbox.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style x:Key="cbStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Chk,Path=IsChecked}" Value="True">
<Setter Property="Text" Value="{x:Null}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<CheckBox Name="Chk" Content="test"/>
<TextBox Style="{StaticResource cbStyle}">
</TextBox>
</StackPanel>
</Window>

Unlike an animation which can "hold" a dependency property at a specified value once the animation ends, a DataTrigger sets the target property and then is done until the source property changes.
In other words, in your example if you put some text in the text box, then check the box, the text will be cleared. But then if you start typing in the text box again, DataTrigger isn't going to do anything until the check box changes again. That's why when you uncheck and re-check the box, the text is cleared again.
So what you may want to do is in your DataTrigger, set the text box's IsReadOnly property to true. This will prevent you from typing in the box while the DataTrigger is active.
<DataTrigger Binding="{Binding ElementName=Chk,Path=IsChecked}" Value="True">
<Setter Property="Text" Value="{x:Null}"/>
<Setter Property="IsReadOnly" Value="True"/>
</DataTrigger>

Related

WPF: DataTrigger for Topmost property of Prism Window XAML

I am trying to control the Topmost property of a prism popup window with a DataTrigger, so that when a button within the XAML file is pressed, the Topmost property is set to false. I am pretty new to WPF and am not sure what I need to do to get my binding to work.
Note that the IsModal property is set to false and I'd like to keep it that way, unless the IsModal feature could also be styled with a DataTrigger from the button.
Here's the prism Popup with the style and attempted trigger
<prism:InteractionRequestTrigger SourceObject="{Binding DataBarChartRequest, Mode=OneWay}">
<prism:PopupWindowAction IsModal="False" WindowStartupLocation="CenterScreen">
<prism:PopupWindowAction.WindowStyle>
<Style TargetType="{x:Type Window}">
<Setter Property="Topmost" Value="True"/>
<Setter Property="Height" Value="650"/>
<Setter Property="Width" Value="900"/>
<Setter Property="ResizeMode" Value="CanResize"/>
<Setter Property="ShowInTaskbar" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=StopButton, Path=IsPressed}" Value="True">
<Setter Property="Window.Topmost" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</prism:PopupWindowAction.WindowStyle>
<prism:PopupWindowAction.WindowContent>
<local:DataBarChartNotificationView Width="NaN" Height="NaN" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>
</prism:InteractionRequestTrigger>
and here's the button
<RibbonButton Label="Stop"
x:Name="StopButton"
Command="{Binding StopSessionCommand}"
LargeImageSource ="{StaticResource SessionStopGray}"
FontSize="12"
FontWeight="Regular"
Height="60"
Margin="0,10,0,0"
Foreground="White"/>
It seems as though, despite this InteractionRequestTrigger being in the same xaml file as my button, the prism popup cannot find this local source, or it simply won't work. Would like to know if I can style either the IsModal or Topmost property with the button in the XAML file as a DataTrigger or how to fix my binding to do so.

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>

ControlTemplate and validation - How to position items?

I created ControlTemplate which is shown if there are validation error on my textbox. My controltemplate looks like that
<ControlTemplate x:Key="TextBoxErrorTemplate">
<TextBlock Foreground="Orange" FontSize="12pt">Field can't be empty</TextBlock>
</ControlTemplate>
However if validation errors occure textBlock appears on textBox - and the user can't enter proper value. Is there any way to set the position of TextBlock - the one which shows error info?
ErrorTemplates are for adorning the control and not for changing its internal properties, to do this you should use a style with the respective trigger:
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Foreground" Value="Orange"/>
<Setter Property="FontSize" Value="12"/>
</Trigger>
</Style.Triggers>
</Style>
If you want to display some text you could use a template like this:
<ControlTemplate x:Key="TextBoxErrorTemplate">
<StackPanel Orientation="Horizontal">
<AdornedElementPlaceholder/>
<TextBlock Foreground="Orange" FontSize="12pt">Field can't be empty</TextBlock>
</StackPanel>
</ControlTemplate>
The TextBlock will be displayed on the right of the TextBox.
If you just want to show error messages i'd suggest you set the tooltip of the TextBox and bind it to the validation errors.

changing background color of container when textbox is in focus

I have a simple user control with a TextBox. I want to change the color of user control when the TextBox gets the focus. This is what I have:
<UserControl x:Class="OutLookContactList.ContactSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root" MinHeight="30" Loaded="UserControl_Loaded">
<UserControl.Resources>
<Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter TargetName="root" Property="Background" Value="{StaticResource OnMouseOverColor}" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
But I get the errot "TargetName property cannot be set on a style Setter". How can I Set the back ground color of user control when text box gets the focus?
Thanks a bunch
Will it work to wrap the contents of your UserControl inside a Border object? If so, you can simply style the Border like so:
<UserControl x:Class="Sample2.ContactSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="75" Width="300">
<Border>
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocused, ElementName=txtSearch}" Value="true">
<Setter Property="Background" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel>
<TextBox x:Name="txtSearch" Text="Search" />
<TextBox Text="Other" />
</StackPanel>
</Border>
</UserControl>
Update: (Answering Sheraz' Questions)
I'm not sure why ElementName doesn't work for accessing children within a UserControl. It might have something to do with the way the visual tree is constructed.
As for Trigger vs DataTrigger: Trigger is for dependency properties and DataTrigger is for databound properties (data or other controls). Since you are trying to style the Border, it makes more sense to place the DataTrigger there and have it watch the TextBox than to have the TextBox change the appearance of the Border.
As I understand it, the TargetName property of Setter is only applicable within a DataTemplate or ControlTemplate. (Info from Dr. WPF in this forum post)
If you were changing the background of the text box you need to remove the TargetName property:
<Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Background" Value="{StaticResource OnMouseOverColor}" />
</Trigger>
</Style.Triggers>
</Style>
and change the TextBox that wants this style to be:
<TextBox Style="{StaticResource searchTextBoxStyle}" .... />
However, as you want to change the value of the parent user control this won't give you want you want.
You could certainly do it in the code behind by adding a GotFocus event handler and putting the code to change the background colour in there.
Here's some XAML that works in Kaxaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Style>
<Style TargetType="Page">
<Setter Property="Background" Value="#CCCCD0" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=txtSearch, Path=IsFocused}"
Value="true">
<Setter Property="Background" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</Page.Style>
<TextBox x:Name="txtSearch" Width="100"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Page>
You would change the Page object with your UserControl. I find it much easier to test these sorts of things out in a rapid prototyping tool such as Kaxaml before coding up the UserControl in VS.
Note that you have to set the default colour (in this case #CCCCD0) via a property setter and not via an attribute on the Page itself. This is because the attribute would override the value set by the trigger (because it's a style trigger), so even though the trigger would fire, it would always be trumpted by the local attribute specification, meaning that it wouldn't change. I only point this out because it's a fairly common gotcha.

TextBlock Text property can't be set via style trigger if non-empty - why?

The XAML below does not work (the text does not change when mousing over):
<Window.Resources>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Text" Value="hover"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<TextBlock Text="original"/>
</Grid>
But, if the Text attribute is missing:
<Grid>
<TextBlock/>
</Grid>
The text does change on mouse over. Anybody knows the theory behind this?
It's a DependencyProperty precedence issue, when you actually set the property as in:
<TextBlock Text="original"/>
that takes precedence over the value set in the trigger.
see
http://msdn.microsoft.com/en-us/library/ms743230.aspx

Resources