Reputation: 2428
I started a new little WPF application which has something like an entry form that is placed over a picture. That picture has the placeholders for the data that should be entered and where TextBoxes are placed so the user is actually entering the data into a form as she would do by hand or in a typewriter. I wanted to add an effect, partiali hiding the textbox when the user leaves the field so placed some event handlers in one of the fields adding this code:
<TextBox Height="23" VerticalAlignment="Top" Width="237"
HorizontalAlignment="Left" Margin="641,25,0,0"
Name="txtAmount" LostFocus="txtAmount_LostFocus" />
private void txtAmount_LostFocus(object sender, RoutedEventArgs e)
{
Opacity = .5;
}
That worked so I continued adding code to set the same behavior in all textBoxes, so I changed the code above with the code below:
<Window.Resources>
<Storyboard x:Key="FadeOut">
<DoubleAnimation From="1.0" To="0.5"
Duration="0:0:0.2"
Storyboard.TargetProperty="Opacity">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="FadeIn">
<DoubleAnimation From="0.5" To="1.0"
Duration="0:0:0.2"
Storyboard.TargetProperty="Opacity"/>
</Storyboard>
<Style x:Key="InTheShadow" >
<Style.Setters>
<Setter Property="TextBox.Opacity" Value="0.5" />
</Style.Setters>
</Style.Setters>
<Style.Triggers>
<EventTrigger RoutedEvent="TextBox.GotFocus">
<BeginStoryboard Storyboard="{StaticResource FadeIn}"/>
</EventTrigger>
<EventTrigger RoutedEvent="TextBox.LostFocus">
<BeginStoryboard Storyboard="{StaticResource FadeOut}"/>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
The first code, also had GotFocus event handled but it's almost the same code, so the second code implemented that, and that was placed on all textBoxes setting the style.
Now, this worked too but, I wanted to add the same effect for MouseEnter/MouseLeave
<EventTrigger RoutedEvent="TextBox.MouseEnter">
<BeginStoryboard Storyboard="{StaticResource FadeIn}"/>
</EventTrigger>
<EventTrigger RoutedEvent="TextBox.MouseLeave">
<BeginStoryboard Storyboard="{StaticResource FadeOut}"/>
</EventTrigger>
but, here my question comes, those events obviously changed the Opacity always, and that was not my intention. I didn't want to change the Opacity for the TextBox that had the Focus, I wanted to keep that Opacity in 100%.
Upvotes: 2
Views: 2050
Reputation: 32725
MultiTriggers to the rescue!
Care also had to be taken to stop the old storyboards. Hopefully this works as you expected:
<Style x:Key="InTheShadow" TargetType="TextBox">
<Setter Property="TextBox.Opacity" Value="0.5" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="False" />
<Condition Property="IsMouseOver" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="fadeOut1" />
<StopStoryboard BeginStoryboardName="fadeOut2" />
<BeginStoryboard x:Name="fadeIn1" Storyboard="{StaticResource FadeIn}"/>
</MultiTrigger.EnterActions>
<MultiTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="fadeIn1" />
<StopStoryboard BeginStoryboardName="fadeIn2" />
<BeginStoryboard x:Name="fadeOut1" Storyboard="{StaticResource FadeOut}"/>
</MultiTrigger.ExitActions>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="fadeOut1" />
<StopStoryboard BeginStoryboardName="fadeOut2" />
<BeginStoryboard x:Name="fadeIn2" Storyboard="{StaticResource FadeIn}"/>
</MultiTrigger.EnterActions>
<MultiTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="fadeIn1" />
<StopStoryboard BeginStoryboardName="fadeIn2" />
<BeginStoryboard x:Name="fadeOut2" Storyboard="{StaticResource FadeOut}"/>
</MultiTrigger.ExitActions>
</MultiTrigger>
</Style.Triggers>
</Style>
Usage:
<StackPanel Margin="7">
<TextBox Margin="7" Style="{StaticResource InTheShadow}" />
<TextBox Margin="7" Style="{StaticResource InTheShadow}" />
<TextBox Margin="7" Style="{StaticResource InTheShadow}" />
<TextBox Margin="7" Style="{StaticResource InTheShadow}" />
<TextBox Margin="7" Style="{StaticResource InTheShadow}" />
</StackPanel>
Edit: Also, you should remove the "from" in your storyboards, that way if the text box already had mouse over and you focus, it won't re-animate:
<Storyboard x:Key="FadeOut">
<DoubleAnimation
To="0.5"
Duration="0:0:0.2"
Storyboard.TargetProperty="Opacity" FillBehavior="HoldEnd"
/>
</Storyboard>
<Storyboard x:Key="FadeIn">
<DoubleAnimation
To="1.0"
Duration="0:0:0.2"
Storyboard.TargetProperty="Opacity" FillBehavior="HoldEnd"
/>
</Storyboard>
Upvotes: 6