Trigger on other element with SourcName - wpf

I want to enable / disable button by Validation.HasError of a text box. (With Storyboard)
I tried to do it in the following way:
Storyboard :
<Window.Resources>
<Storyboard x:Key="SB" x:Name="SB">
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.IsEnabled)">
<DiscreteBooleanKeyFrame KeyTime="0" Value="False"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
Textbox: (Bind to Num - only int)
<TextBox x:Name="txt1" Grid.Row="1" Text="{Binding Num}" Height="50" Width="200">
Button:
<Button x:Name="Btn1" Height="50" Width="200" Content="My Button">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=txt1, Path=Validation.HasError}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource SB}"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="SB"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
It does not work.
If I put the Style, on the TextBox in the following, it works (it does not allow the TextBox):
<TextBox x:Name="txt1" Grid.Row="1" Text="{Binding Num}" Height="50" Width="200">
<TextBox.Style>
<Style>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource SB}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="SB"/>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The problem is that I can not set SourceName on Trigger like this and put it in the same way on the the button.
If I do that I get error:
SourceName property cannot be set within Style.Triggers section.
I'd love some help...

All I was missing, it brackets:
<DataTrigger Binding="{Binding ElementName=txt1,Path=(Validation.HasError)}" Value="True">

Related

Not all DataTriggers of StackPanel are working

I have a button which shows a text and an image:
For this I use a StackPanel with a TextBlock and an Image inside of it.
When the variable "ActiveState" changes the Background of the StackPanel should change too, for this I use DataTriggers
ActiveState=0 -> Red /
ActiveState=1 -> Blue /
ActiveState=2 -> blinking Blue (for this I use a Storyboard and a Color Animation)
The blinking Trigger (Value=2) is working fine, but the two other Triggers (Value=0 + Value=1) are not working.
When I remove the Background of the Stackpanel (Background="Transparent") the first two Triggers are working but the last one get the following Exception:
An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll
Additional information: Background property does not point to a dependencyobject in path '(0).(1)'
This is my code:
<Button>
<Button.Template>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Horizontal" Name="SelectButtonStackpanel" Background="Transparent">
<TextBlock Text="{Binding Text}"/>
<Image Source="{Binding Image}" Stretch="Uniform" Height="40" Width="40"/>
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding ActiveState}" Value="0">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="1">
<Setter Property="Background" Value="Blue"/>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="2">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(StackPanel.Background).(SolidColorBrush.Color)"
To="Blue" Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever"
>
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(StackPanel.Background).(SolidColorBrush.Color)"
Duration="0:0:1"
>
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
Do you have any idea how I get all three Triggers working?
best regards
Phil
When you directly set Background="Transparent" on the StackPanel, this has higher precedence than a value set from a Style Setter. So remove the direct assignment and add another Setter for the default Background.
Besides that, if you want to animate Background.Color you should always explictly assign SolidColorBrushes instead of predefined Brushes like Background="Red".
<StackPanel Orientation="Horizontal" Name="SelectButtonStackpanel">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ActiveState}" Value="0">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Red"/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="1">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Blue"/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="2">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="Background.Color"
To="Blue" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever">
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>

How to bind visibility of a control with context menu item IsChecked property?

(On clicking the menu item , the visibility of the textblock mentioned below should be changed, How can i achieve this using data binding)
**<MenuItem Header="Lat/Long Info" IsCheckable="True" IsChecked="True"/>**
</ContextMenu>
</Window.Resources>
<Grid>
<Button Content="MENU" Height="20" Width="100" Margin="0,10" HorizontalAlignment="Left" VerticalAlignment="Top">
<Button.LayoutTransform>
<RotateTransform Angle="-90"/>
</Button.LayoutTransform>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Button.Background" Value="Black"/>
<Setter Property="Button.Foreground" Value="White"/>
<Setter Property="ContextMenu" Value="{StaticResource conmenu}"/>
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
**<TextBlock Text="Change my Visibility" Margin="50"></TextBlock>**
</Grid>
Please anyone help me with this issue , I am unable to find any solution

datatrigger cannot set bound property

I have 2 checkboxes (chkMfsUi and chkMfs). When I check chkMfsUi, I also want to check chkMfs (and disable it).
I tried it with a datatrigger:
<Style x:Key="MfsCheckBoxStyle" TargetType="CheckBox">
<Setter Property="IsEnabled" Value="True" />
<Setter Property="IsChecked" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=chkMfsUi}" Value="True">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="IsChecked" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
And these are my checkboxes:
<StackPanel>
<CheckBox Name="chkMfsUi"
Checked="CheckBox_Checked"
Content="MFS - UI"
IsChecked="{Binding MfsUi}"
Unchecked="CheckBox_Checked" />
<CheckBox Content="MFS" IsChecked="{Binding Mfs}" Style="{StaticResource MfsCheckBoxStyle}" />
</StackPanel>
The IsEnabled property work fine, but the IsChecked doesn't. Maybe because it is bound? I am also using INotifyPropertyChanged with these properties.
If I set it in code behind, it works, but is it possible with a trigger though?
Regards,
Alfons
EDIT:
As appeared from the current answers, my question seems to be incomplete. I need to have the following three states:
AND last but not least: Both checkboxes' IsChecked properties must be bound! (This is the moment when the trouble comes in)
Try this
<StackPanel Grid.Column="1">
<CheckBox x:Name="chkMfsUi" IsChecked="True"></CheckBox>
<CheckBox x:Name="chkMfs" IsChecked="{Binding ElementName=chkMfsUi,Path=IsChecked}">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</Trigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
Another Method : By using style in resource
Add this namespace first xmlns:Globalvaribale="clr-namespace:System;assembly=mscorlib"
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Globalvaribale="clr-namespace:System;assembly=mscorlib">
<Window.Resources>
<Globalvaribale:String x:Key="chkMfsUi">chkMfsUi</Globalvaribale:String>
<Style x:Key="chkMfsstyle" TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,ElementName={StaticResource chkMfsUi}}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Grid.Column="1">
<CheckBox x:Name="chkMfsUi"></CheckBox>
<CheckBox Style="{StaticResource chkMfsstyle}"/>
</StackPanel>
Output
In this case you can use the EventTrigger:
Represents a trigger that applies a set of actions in response to an event.
Example:
<StackPanel>
<StackPanel.Triggers>
<EventTrigger RoutedEvent="CheckBox.Checked" SourceName="First">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="Second"
Storyboard.TargetProperty="IsChecked">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="CheckBox.Checked" SourceName="Second">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="First"
Storyboard.TargetProperty="IsChecked">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="CheckBox.Unchecked" SourceName="First">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="Second"
Storyboard.TargetProperty="IsChecked">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="CheckBox.Unchecked" SourceName="Second">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="First"
Storyboard.TargetProperty="IsChecked">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</StackPanel.Triggers>
<CheckBox Name="First"
Content="First" />
<CheckBox Name="Second"
Content="Second" />
</StackPanel>
The Storyboard can be stored in Resources for readability, like so:
<Window.Resources>
<Storyboard x:Key="FirstCheckedStory" ... />
</Window.Resources>
And then use like this:
<EventTrigger RoutedEvent="CheckBox.Checked" SourceName="First">
<BeginStoryboard Storyboard="{StaticResource FirstCheckedStory}" />
</EventTrigger>
Also, the Storyboard can contain several actions, just put him in order:
<Storyboard>
<BooleanAnimationUsingKeyFrames ... />
<BooleanAnimationUsingKeyFrames ... />
</Storyboard>

Button blinking on Datatrigger

I would like to have a button that blinks/animate when triggered by DataTrigger. I want to animate the button's background. Below is my xaml code.
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid>
<Button x:Name="Button" Content="Button" Width="25" Height="25" Margin="158,62,320,224" Click="Button_Click"></Button>
<Button Style="{StaticResource ButtonStyle}" Content="Button" Focusable="False" Height="75" HorizontalAlignment="Left" Margin="23,146,0,0" Name="btnImgBrush" VerticalAlignment="Top" Width="160"></Button>
</Grid>
</Grid>
Here are the back end code:
public Boolean Notification
{
get { return new_notification; }
set
{
new_notification = value;
RaisePropertyChanged("Notification");
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (Notification)
{
Notification = false;
}
else
{
Notification = true;
}
}
But, it didn't work. Any ideas why it didn't work?
Any help is greatly appreciated, Thanks.
At last its working. Thanks :)
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
Try this-
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Notification,RelativeSource={RelativeSource AncestorType=Window}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" From="Transparent" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Notification,,RelativeSource={RelativeSource AncestorType=Window}}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
Both TM Rocket and Vishal answer are correct but probably the following is the most correct and clean way to do it
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>

How to delay the Setter to be in affect for 0.5 sec in DataTrigger?

I am wondering if it possible to delay a datatrigger to change layout for 0.5 a second. Is any easy way to do it? I need to set the visibility of the object but wait for 0.5 a second. Any adeas are highly appreciated.
<DataTemplate x:Key="ListBoxItemDataTemplate">
<Grid x:Name="DataItem">
<Image x:Name="IconImage" Source="{Binding XPath=#icon}" Height="16" Margin="16,0,0,0" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock x:Name="ListboxIemtextBlock" Text="{Binding XPath=#name}" />
<Image x:Name="ArrowImage" Height="10" Source="Resources/Images/arrow_collapsed_grey.png" Visibility="{Binding XPath=#state}"/>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}, Mode=FindAncestor}}" Value="True">
<Setter TargetName="ListboxIemtextBlock" Property="Foreground" Value="White"/>
<Setter TargetName="IconImage" Property="Source" Value="{Binding XPath=#iconSelected}"/>
<Setter TargetName="IconImage" Property="Height" Value="16"/>
<Setter TargetName="ArrowImage" Property="Source" Value="Resources/Images/arrow_collapsed_white.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}, Mode=FindAncestor}}" Value="True">
<Setter TargetName="ListboxIemtextBlock" Property="Foreground" Value="#FF6dacbe"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}}, Path=SelectedItem.Attributes[retract].Value}" Value="True">
<Setter TargetName="ListboxIemtextBlock" Property="Visibility" Value="Hidden" />
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartAnimation" Storyboard="{StaticResource MakeObjectVisibleAfterHalfASecond}"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="StartAnimation"/>
</DataTrigger.ExitActions>
</DataTrigger>
</DataTemplate.Triggers></DataTemplate>
Storyaboard:
<Storyboard x:Key="MakeObjectVisibleAfterHalfASecond" Storyboard.TargetName="ListboxIemtextBlock">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Duration="0" BeginTime="0:0:.5">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
It can be done using an animation. The pieces involved are:
1) An ObjectAnimationUsingKeyFrames that sets the Visibility property on the target, with a BeginTime of 0:0:.5 to delay this for a half second when the storyboard begins.
2) A DataTrigger that checks the property whose change will make the object visible (in this case, the IsChecked property on the CheckBox named Start).
3) BeginStoryboard in DataTrigger.EnterActions that launches the animation, and a RemoveStoryboard in DataTrigger.ExitActions that makes the object invisible again if the bound property changes back.
Here's a simple working example:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Storyboard x:Key="MakeObjectVisibleAfterHalfASecond">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility"
Duration="0"
BeginTime="0:0:.5">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<DockPanel>
<CheckBox DockPanel.Dock="Top"
Margin="10"
x:Name="Start">Check this to make the label appear</CheckBox>
<Border BorderThickness="2"
BorderBrush="AliceBlue"
CornerRadius="5"
Margin="10"
Padding="10"
DockPanel.Dock="Top">
<Label Visibility="Hidden">
<Label.Content>This should appear a half second after the box is checked.</Label.Content>
<Label.Style>
<Style TargetType="Label">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Start, Path=IsChecked}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartAnimation"
Storyboard="{StaticResource MakeObjectVisibleAfterHalfASecond}"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="StartAnimation"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
</Border>
<TextBlock/>
</DockPanel>
</Page>
Note that you could also do this by omitting BeginTime and setting Duration on the animation, since the two are essentially the same thing with a key-frame animation.

Resources