i want to create an animation where each word of a line changes its foreground color from black to white after some intervals.
initially all the words are set to black.
i have used this code:
DispatcherTimer text1timer = new DispatcherTimer();
text1timer.Interval = TimeSpan.FromMilliseconds(440);
text1timer.Tick += text1timer_Tick;
text1timer.Start();
void text1timer_Tick(object sender, object e)
{
text1timer.Tick -= text1timer_Tick;
txt1.Foreground = new SolidColorBrush(Colors.White);
text1timer.Stop();
text1timer.Tick += text2timer_Tick;
text1timer.Start();
}
private void text2timer_Tick(object sender, object e)
{
text1timer.Tick -= text2timer_Tick;
txt2.Foreground = new SolidColorBrush(Colors.White);
text1timer.Stop();
text1timer.Tick += text3timer_Tick;
text1timer.Start();
}
private void text3timer_Tick(object sender, object e)
{
text1timer.Tick -= text3timer_Tick;
txt3.Foreground = new SolidColorBrush(Colors.White);
text1timer.Stop();
text1timer.Tick += text4timer_Tick;
text1timer.Start();
}
and so on but i have more than 100 words and i will have to make more than 100 events of the timer.is there any other solution?
You can use StoryBoard for the desired functionality.Check the following codes.
<Page.Resources>
<Storyboard x:Name="TextForegroundSb" RepeatBehavior="Forever">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Tag)" Storyboard.TargetName="textBlock">
<DiscreteObjectKeyFrame KeyTime="0:0:0.0" Value="Red"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.2" Value="Green"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.4" Value="Blue"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
Here is the Textblock
<TextBlock x:Name="textBlock" TextWrapping="Wrap" Text="TextBlock" FontSize="48" Tag="Red" FontWeight="Bold" Foreground="{Binding Tag, RelativeSource={RelativeSource Mode=Self}}" FontFamily="Global User Interface" />
Also you can modify the time by changing DiscreteObjectKeyFrame KeyTime property.
For playing the storyboard on a button click use this code.
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" <br/>
xmlns:Core="using:Microsoft.Xaml.Interactions.Core" <br/>
xmlns:Media="using:Microsoft.Xaml.Interactions.Media" <br/>
<Button Content="Start sb" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="915,285,0,0" Height="119" Width="276">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Click">
<Media:ControlStoryboardAction Storyboard="{StaticResource TextForegroundSb}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Button>
Hope this helps.
Thanks..
Use storyboard! there are instructions online and on MSDN.
Related
I have code like this
<Storyboard x:Key="AdvMarquee" Completed="Storyboard_Completed">
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" From="-25" To="0" BeginTime="0:00:00" Duration="0:00:01" />
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" From="0" To="25" BeginTime="0:00:03" Duration="0:00:01" />
</Storyboard>
<Style x:Key="AnimationImageStyle" TargetType="StackPanel">
<Setter Property="Canvas.Top" Value="200" />
<Style.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard Storyboard="{StaticResource AdvMarquee}"/>
</EventTrigger>
</Style.Triggers>
</Style>
And Applied this Animation style with this code
<Canvas x:Name="Advertise" Background="{x:Null}" Margin="10,0,0,0" >
<StackPanel Style="{StaticResource AnimationImageStyle}">
<Button Click="Advertise_Click" Style="{StaticResource AdvertisementBtnStyle}">
<TextBlock Name="AdvText" Text="This is Animated Text" Padding="10, 0, 10, 0"/>
</Button>
</StackPanel>
</Canvas>
I've tried to use Completed Event on Storyboard to calculate how many times Storyboard animation executed.
Before this, I tried to add RepeatBehavior="Forever" on Storyboard but it just loop forever and didn't run completed event.
and now, when I remove RepeatBehavior="Forever", it complete it's progress, count up, but it doesn't run again.
how can I solve this problem?
still have no idea cuz I'm really new to work with xaml wpfform.
My Storyboard_Completed is just like this.
int count = 0;
private void Storyboard_Completed( object sender, EventArgs e )
{
count++;
}
Put event handler for CurrentStateInvalidated for the last animation and you will have the possibility to get current iteration:
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" From="0" To="25" BeginTime="0:00:03" Duration="0:00:01" CurrentStateInvalidated="DoubleAnimation_CurrentStateInvalidated"/>
int cnt=0;
private void DoubleAnimation_CurrentStateInvalidated(object sender, EventArgs e)
{
var ac = sender as AnimationClock;
cnt = (ac.Parent as ClockGroup).CurrentIteration;
}
Storyboard_Completed you will not need.
I am animating the ellipse to move horizontally in wpf. Now I want to add few more ellipses on to the canvas when ellipse reaches certain point on canvas (let's say midpoint of the canvas). How can I achieve this?
XAML code-
<Canvas Background="AliceBlue" x:Name="canvas">
<Ellipse
Name="ellipse1"
Canvas.Left="50"
Fill="#FFFFFF00"
Height="75"
Width="100"
/>
</Canvas>
Code behind-
public partial class MainWindow : Window
{
private DoubleAnimation anim = new System.Windows.Media.Animation.DoubleAnimation(50, 400, TimeSpan.FromSeconds(10),
System.Windows.Media.Animation.FillBehavior.HoldEnd);
private AnimationClock clock;
public MainWindow()
{
InitializeComponent();
clock = anim.CreateClock();
this.ellipse1.ApplyAnimationClock(Canvas.LeftProperty, clock);
}
}
Initially I thought it was simple, I would just access Canvas.Left from code behind and when it reaches the value I want, I would add the ellipses. But I am struggling to implement this, I guess I would need some kind of watcher or event to achieve this. How should I implement it?
Create two storyboards. Each one does half the animation. When the first storyboard completes start the second storyboard and add the other ellipses.
XAML
<Window.Resources>
<Storyboard x:Key="StartingStoryboard"
Completed='Storyboard_Completed'>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
Storyboard.TargetName="ellipse1">
<EasingDoubleKeyFrame KeyTime="0"
Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:2"
Value="100" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="EndingStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
Storyboard.TargetName="ellipse1">
<EasingDoubleKeyFrame KeyTime="0"
Value="100" />
<EasingDoubleKeyFrame KeyTime="0:0:2"
Value="200" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource StartingStoryboard}" />
</EventTrigger>
</Window.Triggers>
<Canvas Background="AliceBlue"
x:Name="canvas1">
<Ellipse Name="ellipse1"
Fill="#FFFFFF00"
Height="75"
Width="100"
RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform />
<TranslateTransform />
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Canvas>
Code
private void Storyboard_Completed(object sender, EventArgs e) {
var sb = FindResource("EndingStoryboard") as Storyboard;
sb.Begin();
var orangeEllipse = new Ellipse();
orangeEllipse.Fill = new SolidColorBrush(Colors.Orange);
orangeEllipse.Width = orangeEllipse.Height = 40;
canvas1.Children.Add(orangeEllipse);
}
I am using this code
Hello.Background = System.Windows.Media.Brushes.Blue;
var dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = TimeSpan.FromSeconds(61);
TimeSpan span = new TimeSpan(0,1,0);
dispatcherTimer.Start();
dispatcherTimer.Tick += delegate
{
if (dispatcherTimer.Interval > span)
{
Hello.Background = System.Windows.Media.Brushes.Red;
dispatcherTimer.Stop();
}
};
But button keeps fade in and fade out.
i want color to be constant
C#
private void Button_Click(object sender, RoutedEventArgs e)
{
Hello.Background = System.Windows.Media.Brushes.Blue;
var dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = TimeSpan.FromSeconds(61);
TimeSpan span = new TimeSpan(0,1,0);
dispatcherTimer.Start();
dispatcherTimer.Tick += delegate
{
if (dispatcherTimer.Interval > span)
{
Hello.Background = System.Windows.Media.Brushes.Red;
dispatcherTimer.Stop();
}
};
}
Xaml
<Button Name="Hello" Content="Hello" Background="White" Foreground="Black " Click="Button_Click">
</Button>
You could just create a Style and use a Trigger to start a Storyboard with ColorAnimations
Example:
<Style x:Key="AnimatedButton" TargetType="Button">
<Setter Property="Background" Value="Red" />
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Background.Color">
<ColorAnimation To="Blue" Duration="0:0:4" />
<ColorAnimation To="Red" BeginTime="0:1:52" Duration="0:0:4" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
Just tried it now ..... however this is code behind
XAML Code:
<Button Content="Button" x:Name="MyButton" Height="23" HorizontalAlignment="Left"
Margin="94,128,0,0" VerticalAlignment="Top" Width="75"/>
Cs File
private void StartAnimation()
{
Color fromRGB= Color.FromRgb(255, 255, 255); ;
Color ToRGB= Color.FromRgb(255, 0, 0);
SolidColorBrush myBrush = new SolidColorBrush();
myBrush.Color = Colors.Black;
ColorAnimation myAnimation = new ColorAnimation();
myAnimation.From = fromRGB;
myAnimation.To = ToRGB;
myAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(120000));
myAnimation.AutoReverse = true;
myBrush.BeginAnimation(SolidColorBrush.ColorProperty, myAnimation );
MyButton.Background = myBrush;
}
you can change the color when your event is called and then call your animation.
Just to show a different approach really ... If you're using MVVM, you could bind your button color to a property on the ViewModel, and once you click on it, run your 2 minutes background/timer . Once the 2 minutes are done, it'll change the color to the other one.
Not much xaml involved, and I do like some of the other solutions here :)
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(2000); // two second
ButtonColorPropertyName= Colors.Red;
}
(Assuming you have the ButtonColorPropertyName or whatever you want to name it, in the ViewModel)
could you try to use a simple StoryBoard created in Blend and then apply to Button/style
something like this:
<Button Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="button1" VerticalAlignment="Top" Width="75" >
<Button.Background>
<SolidColorBrush x:Name="MySolidColorBrush" Color="Brown" />
</Button.Background>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="MySolidColorBrush"
Storyboard.TargetProperty="Color"
From="Red" To="Yellow" Duration="0:0:0" RepeatBehavior="1x" />
<ColorAnimation
Storyboard.TargetName="MySolidColorBrush"
Storyboard.TargetProperty="Color"
From="Yellow" To="Blue" Duration="0:0:0" RepeatBehavior="1x" BeginTime="0:0:10" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
How to stop an animation so it won't produce Completed event. Here's simple example
<Window x:Class="WpfApplication5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="248" Width="318">
<Grid>
<Border Width="20" Height="20" Background="Red" MouseEnter="Border_MouseEnter" MouseLeave="Border_MouseLeave" x:Name="border" />
</Grid>
</Window>
And backing code:
private void Border_MouseEnter(object sender, MouseEventArgs e)
{
var a = new DoubleAnimation { To = 0, Duration = TimeSpan.FromMilliseconds(4000) };
a.Completed += (obj, args) => MessageBox.Show("Boom!");
border.BeginAnimation(Border.OpacityProperty, a);
}
private void Border_MouseLeave(object sender, MouseEventArgs e)
{
border.BeginAnimation(Border.OpacityProperty, null);
border.Opacity = 1;
}
If I move mouse out before rectangle becomes white it still will display popup window after some time. How to prevent this? Let's assume that Border_MouseLeave and Border_MouseEnter methods doesn't know about each other (they can't pass animation instance variable to each other).
you can use this:
<Border Width="20" Height="20" Background="Red" x:Name="border" >
<Border.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard Name="Ali">
<Storyboard>
<DoubleAnimation To="0" Duration="0:0:4" Completed="com" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<StopStoryboard BeginStoryboardName="Ali"/>
</EventTrigger>
</Border.Triggers>
</Border>
and :
private void com(object sender, EventArgs e)
{
MessageBox.Show("boom!");
}
You could use Property or Data Trigger's EnterActions and ExitActions properties or as #Ali said correctly use Begin and Stop storyboard.
I m stuck with a problem. I want to change the background image of button on runtime. I got the solution for changing the color but i want to change the image.
The code is as follows
public void buttonCase(object sender, RoutedEventArgs e)
{
Uri uri = null;
var image = new ImageBrush();
if (((App)App.Current).appControler.m_Mode == Controller.textMode.Letters)
{
((App)App.Current).appControler.buttonCase(sender, e);
switch (((App)App.Current).appControler.m_case)
{
case Controller.caseMode.Upper:
b0.FontSize = b1.FontSize = b2.FontSize = b3.FontSize = b4.FontSize = b5.FontSize = b6.FontSize = b7.FontSize
= b8.FontSize = b9.FontSize = bCornerLower.FontSize = 30.0;
uri = new Uri(#"/SourceCode;component/Images/Lower_Case_p.png", UriKind.Relative);
image.ImageSource = new BitmapImage(uri);
btnCase.Background = image;
break;
case Controller.caseMode.Lower:
b0.FontSize = b1.FontSize = b2.FontSize = b3.FontSize = b4.FontSize = b5.FontSize = b6.FontSize = b7.FontSize
= b8.FontSize = b9.FontSize = bCornerLower.FontSize = 40.0;
uri = new Uri(#"/SourceCode;component/Images/Case_p.png", UriKind.Relative);
image.ImageSource = new BitmapImage(uri);
btnCase.Background = image;
break;
}
}
}
Something like this?
var brush = new ImageBrush();
brush.ImageSource = new BitmapImage(new Uri(#"Images/myImage.png", UriKind.Relative));
myButton.Background = brush;
[Edit] I made a test application with two images. I toggle the image on button click and it works.
private bool flag;
private void button1_Click(object sender, RoutedEventArgs e)
{
flag = !flag;
var uriString = flag ? #"Images/logo.png" : #"Images/icon.png";
myButton.Background = new ImageBrush
{ ImageSource = new BitmapImage(new Uri(uriString, UriKind.Relative)) };
}
private void button_Click(object sender, EventArgs e)
{
button.Image=System.Drawing.Image.FromFile("image.png");
}
try this..
Utilize VisualStates for this kind of UI state switching.
Your code behind would look like this:
public void buttonCase(object sender, RoutedEventArgs e)
{
if (((App)App.Current).appControler.m_Mode == Controller.textMode.Letters)
{
((App)App.Current).appControler.buttonCase(sender, e);
switch (((App)App.Current).appControler.m_case)
{
case Controller.caseMode.Upper:
VisualStateManager.GoToState( this, "UpperCase", true );
break;
case Controller.caseMode.Lower:
VisualStateManager.GoToState( this, "LowerCase", true );
break;
}
}
}
And your xaml would look like this:
<UserControl
x:Class="SilverlightApplication2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<UserControl.Resources>
<ControlTemplate x:Key="MySpecialToggleButton" TargetType="ToggleButton">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="LowerCaseIcon">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="UpperCaseIcon">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Image x:Name="UpperCaseIcon" Source="/SilverlightApplication2;component/Images/Lower_Case_p.png" Visibility="Visible"/>
<Image x:Name="LowerCaseIcon" Source="/SilverlightApplication2;component/Images/Case_p.png" Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<StackPanel>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="LetterCaseStates">
<VisualState x:Name="UpperCase"/>
<VisualState x:Name="LowerCase">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="FontSize" Storyboard.TargetName="bCornerLower">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<system:Double>40</system:Double>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ToggleButton x:Name="btnCase" Click="buttonCase" Template="{StaticResource MySpecialToggleButton}"/>
<Button x:Name="bCornerLower" FontSize="30"/><!-- this one is the styling master, all other buttons follow its styling -->
<Button x:Name="b0" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
<Button x:Name="b1" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
<Button x:Name="b2" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
<Button x:Name="b3" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
<Button x:Name="b4" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
<Button x:Name="b5" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
<Button x:Name="b6" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
<Button x:Name="b7" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
<Button x:Name="b8" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
<Button x:Name="b9" FontSize="{Binding ElementName=bCornerLower, Path=FontSize}"/>
</StackPanel>
I wrote the code as an answer to a similar question here:toggle button with different images
I know that defining VisualStates can look quite cumbersome, but in the end you can keep your code behind quite clean from switching visual appearance of all the ui bits and pieces.