Animating text color - wpf

I need to animate the text color of a custom control between two colors, which are read from two Brush properties of the custom control. My resources look like this:
<SolidColorBrush x:Key="TextBrush">{TemplateBinding Foreground}</SolidColorBrush>
<SolidColorBrush x:Key="AltTextBrush">{TemplateBinding ForegroundAlt}</SolidColorBrush>
Right now, I am trying to animate using a ColorAnimation:
<ColorAnimation Storyboard.TargetName="MyControlText" Storyboard.TargetProperty="Foreground" To="{StaticResource AltTextBrush}" Duration="00:00:00.3000000" />
The ColorAnimation seems to want a Color object, rather than the Brush I am trying to pass. I think I can write an IValueConverter to get the color from the brush, but before I do that, I want to see if there is a simpler way to do the job. Here are my questions:
-- Is there a simple way to animate between two brush resources, or do I need to extract the color for animation?
-- If I need to extract the colors, is an IValueConverter best practice?
-- And finally, amI headed down the right road, or is there a simpler solution to this problem?
Thanks for your help.

Tried with using a Binding and it seems to be working like this
To="{Binding Source={StaticResource TextBrush}, Path=Color}"
Here's a xaml example
<Window.Resources>
<SolidColorBrush x:Key="TextBrush">Black</SolidColorBrush>
<Storyboard x:Key="blinkAnimation" Duration="0:0:5" >
<ColorAnimation Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
Storyboard.TargetName="TitleTextBlock"
To="{Binding Source={StaticResource TextBrush}, Path=Color}"
AutoReverse="True"
Duration="0:0:2"/>
</Storyboard>
</Window.Resources>
<Grid Background="Black" Name="grid">
<TextBlock x:Name="TitleTextBlock"
Background="Black"
Text="My Text"
FontSize="32"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Foreground="White">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<StaticResource ResourceKey="blinkAnimation"/>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</Grid>

Related

Adding content/text in rectangle WPF

This is my code for rectangle :
<Rectangle x:Name="rect1" Grid.Column="1" Fill="#FF5C626C" HorizontalAlignment="Left" Height="50" Margin="36,171,0,0" StrokeThickness="2" VerticalAlignment="Top" Width="358" RadiusX="30" RadiusY="50">
<Rectangle.Triggers>
</Rectangle.Triggers>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseEnter">
<BeginStoryboard>
<Storyboard>
<ParallelTimeline >
<ColorAnimation Storyboard.TargetProperty="Fill.Color" To="#FF767C84" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Rectangle.MouseLeave">
<BeginStoryboard>
<Storyboard>
<ParallelTimeline >
<ColorAnimation Storyboard.TargetProperty="Fill.Color" To="#FF5C626C" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
My question is how do i add a text/content in the rectangle ?
One might suggest using a code block, but if u go through my code, youu'll notice that the rectangle changes it's color on mouseover.So if i put a textblock over the rectangle,the mouseover doesn't work properly(as the textblock covers the entire rectangle).
Another suggestion would be to use a border.But i am not sure about this as i need to find the code to apply mouse over effect on a border.
The next suggestion might be to use a button instead.I would've but my rectangle has corner radius and is a bit round-shaped which, if i use a button, would be hard to achieve.
So how do i add content/text inside the rectangle?
If you feel you definitely have to use a rectangle, put it in a grid and add a TextBlock element above it.
By setting the TextBlock's IsHitTestVisible property to False all hit-testing (mouse events) will be ignored on it and fall through to your rectangle.
<Grid>
<Rectangle (...your attributes here...)>
(...your rectangle code here...)
</Rectangle>
<TextBlock Text="Hello World!" IsHitTestVisible="False" />
</Grid>

Quick One regarding Margins and Storyboards

Just a quick question, I've been searching for ages on Google. I have a storyboard:
<Storyboard x:Key="ViewLeftToRight" AccelerationRatio=".5" DecelerationRatio=".5">
<DoubleAnimation Storyboard.TargetName="ReferenceInfo" Storyboard.TargetProperty="Margin" Duration="0:0:0.15" To="{Binding, Width},0,0,0"/>
</Storyboard>
It doesn't work. I was wondering if there is a way for me to bind the Width of the control to the "left" margin. If I need to use a converter, could you possibly show how it would be written in XAML in the above example?
Thanks!
No, you can't bind an animation to Margin, because it does not define a corresponding dependency property. There are several alternatives, here are two:
Place your object in a Canvas and animate Canvas.Left and Canvas.Top
Define a RenderTransform on your object, and animate its X and Y properties.
1)
<Canvas>
<TextBlock Text="test" x:Name="ReferenceInfo" Canvas.Left="0" Canvas.Top="0" />
</Canvas>
Here your storyboard short target the same element ReferenceInfo, but target the attached properties, which you denote using brackets like "(Canvas.Left)":
<DoubleAnimation
Storyboard.TargetName="ReferenceInfo"
Storyboard.TargetProperty="(Canvas.Left)" Duration="0:0:0.15"
To="{Binding Width}"/>
2)
<TextBlock Text="test" x:Name="ReferenceInfo">
<TextBlock.RenderTransform>
<TranslateTransform x:Name="TranslateReferenceInfo" X="0" Y="0" />
</TextBlock.RenderTransform>
</TextBlock>
The animation would then reference the TranslateTransform itself by name:
<DoubleAnimation
Storyboard.TargetName="TranslateReferenceInfo"
Storyboard.TargetProperty="X" Duration="0:0:0.15"
To="{Binding Width}"/>

WPF: Animating a StaticResource updates other controls that use that resource

I have two TextBoxes that use the same StaticResource for their foreground colour.
When I apply an animation that changes the colour of the first TextBox, the colour on the second TextBox is also changed.
This does not happen if I don't use a StaticResource, so I am guessing that the animation is changing the colour of the brush defined in the resource, rather than the foreground colour on the first TextBox.
Here is the code I am using;
<Page.Resources>
<SolidColorBrush x:Key="TextBrush"
Color="Black" />
<Storyboard x:Key="Glow"
TargetProperty="Foreground.Color"
Storyboard.TargetName="txt1">
<ColorAnimation To="Blue"
Duration="0:0:0.1" />
</Storyboard>
<Storyboard x:Key="Normal"
TargetProperty="Foreground.Color"
Storyboard.TargetName="txt1">
<ColorAnimation To="Yellow"
Duration="0:0:0.1" />
</Storyboard>
</Page.Resources>
<StackPanel>
<StackPanel.Triggers>
<EventTrigger RoutedEvent="StackPanel.MouseEnter">
<BeginStoryboard Storyboard="{StaticResource Glow}" />
</EventTrigger>
<EventTrigger RoutedEvent="StackPanel.MouseLeave">
<BeginStoryboard Storyboard="{StaticResource Normal}" />
</EventTrigger>
</StackPanel.Triggers>
<TextBlock Name="txt1"
Foreground="{StaticResource TextBrush}">Text One</TextBlock>
<TextBlock Name="txt2"
Foreground="{StaticResource TextBrush}">Text Two</TextBlock>
</StackPanel>
Is there anyway around this?
Matt
By using a single StaticResource in the binding, changing the Foreground in your animation will change the resource itself. This behavior is by design, as anything else would require full copies of resources, which would very much reduce the usefulness and benefits of using StaticResource in the first place.
The easy workaround, of course, is to not use a StaticResource here, or to use a separate resource per TextBox.

Bind Controls TO standalone animations

i'm new to wpf and i'm try to learn something.
My problem is : i need to bind all that i want to a looping animation...
Example:
<Window x:Class="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">
<StackPanel>
<Slider Visibility="Hidden" Minimum="0" Maximum="100" Height="22" Margin="73,40,105,0" Name="Slider1" VerticalAlignment="Top" Value="0">
<Slider.Triggers>
<EventTrigger RoutedEvent="Slider.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="Slider1"
Storyboard.TargetProperty="Value"
From="0" To="100" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Slider.Triggers>
</Slider>
<Slider Minimum="0" Maximum="100" Height="22" Margin="72,98,106,0" Name="Slider2" VerticalAlignment="Top" Value="{Binding ElementName=Slider1, Path=Value}"/>
<Button Width="{Binding ElementName=Slider1, Path=Value}"></Button>
</StackPanel>
Slider1 is hidden and act as a Source for Slider2 and ButtonWidth.
Like a standalone oscillator.
I need a way to eliminate slider1 and bind directly to a standalone animation that loops.
It is possible?
Thanks in advance :)
Why don't you simply animate the Slider2 Value the same way you've animated Slider1's value? You can also animate the Button's Width. I am not sure why you would need Slider1 in the first place. The following markup demonstrates removing Slider1 and using the animation as a resource:
<Window.Resources>
<DoubleAnimation x:Key="ValueAnimation"
Storyboard.TargetProperty="Value"
From="0" To="100" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Window.Resources>
<StackPanel>
<Slider Minimum="0" Maximum="100" Height="22" Margin="72,98,106,0"
Name="Slider2" VerticalAlignment="Top">
<Slider.Triggers>
<EventTrigger RoutedEvent="Slider.Loaded">
<BeginStoryboard>
<Storyboard Storyboard.TargetName="Slider2">
<StaticResource ResourceKey="ValueAnimation"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Slider.Triggers>
</Slider>
<Button Width="{Binding ElementName=Slider2, Path=Value}"/>
</StackPanel>
You could remove the TargetProperty from ValueAnimation and specify that per animation, as well. That would let you use a single animation for both the Button.Width and the Slider.Value.
thanks for your answer :)
Why don't you simply animate the Slider2 Value the same way you've animated Slider1's value?
because i need to centralize the animation values to share it on multiple objects (not only another slider) and, in this way, i can edit values in 1 place only :)
Thank you your example fits well :)

ControlTemplate.Triggers WPF equivalent in Silverlight 3

I have this controltempalte + trigger stuff in my WPF application.
<ControlTemplate TargetType="me:MyControl" x:Key="fade">
<ContentPresenter - other stuff />
<ControlTemplate.Triggers>
<Trigger Property="IsTransitioned" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation -<stuff>- />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
This works cool in WPF, and is very intuitive too for me to write this based on trigger as above.
When i port this to Silverlight (3), i am told i have to use VSM, states and groups etc. since triggers on control template is not supported.
I h ave looked at some samples, and i even atempted to apply teh VSM bits in, in the place of trigger as above, but can't get it to work.
Someone suggested to me that apart from VSM in the xaml, i will have to handle some events etc.
SL3 model is just being painful for me. Please help.
Silverlight 3 introduced interaction triggers which as far as I can tell do what you want but are a little more complex. There's very few examples about them out yet though.
If you're doing this manually you need references to System.Windows.Interactivity and Microsoft.Expression.Interactions (from Blend 3, the class will be in your references tab if you've installed it).
If you add the triggers in Blend then it will add those automatically. This is called Behaviours in Silverlight 3 and you will find these in Blend in the Behaviours section of the Assets tab.
An example of how they work. Note the storyboard sitting in the resource of the second rectangle, I couldn't get it to work inside the ControlStoryboardAction.Storyboard, but it did work if I made the rectangle a ContentControl and put it in the Template. This may be a bug or me missing something :
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="SLTrigger.MainPage"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
xmlns:im="clr-namespace:Microsoft.Expression.Interactivity.Media;assembly=Microsoft.Expression.Interactions">
<Grid x:Name="LayoutRoot">
<StackPanel>
<Rectangle Margin="5" Fill="Blue" Width="200" Height="100">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<ic:ChangePropertyAction PropertyName="Fill" Duration="0">
<ic:ChangePropertyAction.Value>
<SolidColorBrush Color="Red"/>
</ic:ChangePropertyAction.Value>
</ic:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
<Rectangle Margin="5" x:Name="AnimatedRectangle2" Fill="Blue" Width="200" Height="100">
<Rectangle.Resources>
<Storyboard x:Key="AnimationStoryboard">
<ColorAnimation
Storyboard.TargetName="AnimatedRectangle2"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Red"
AutoReverse="True"
Duration="0:0:0.5" />
</Storyboard>
</Rectangle.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<im:ControlStoryboardAction ControlStoryboardOption="Play" Storyboard="{StaticResource AnimationStoryboard}">
<!--
Doesn't work, but does work inside control templates??
<im:ControlStoryboardAction.Storyboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="AnimatedRectangle2"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Red"
AutoReverse="True"
Duration="0:0:0.5" />
</Storyboard>
</im:ControlStoryboardAction.Storyboard>
-->
</im:ControlStoryboardAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
<ContentControl>
<ContentControl.Template>
<ControlTemplate>
<Rectangle Margin="5" x:Name="AnimatedRectangle3" Fill="Blue" Width="200" Height="100">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<im:ControlStoryboardAction ControlStoryboardOption="Play">
<im:ControlStoryboardAction.Storyboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="AnimatedRectangle3"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Red"
AutoReverse="True"
Duration="0:0:0.5" />
</Storyboard>
</im:ControlStoryboardAction.Storyboard>
</im:ControlStoryboardAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
<TextBlock TextAlignment="Center" Text="Click the rectangles" />
</StackPanel>
</Grid>
</UserControl>
The class file has nothing in it:
using System.Windows.Controls;
namespace SLTrigger
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
}
}

Resources