My Application will download data from the web, whenever the user will trigger. The user can trigger multiple downloads.
Each download is listed in a stack panel an a busy icon is shown on each item which is rotating while downloading.
<Image x:Name="rotatingCircle" Source="{StaticResource busy_icon}" Height="30" RenderTransformOrigin=".5,.5" Visibility="Visible">
<Image.RenderTransform>
<RotateTransform x:Name="AnimatedRotateTransform" Angle="0" />
</Image.RenderTransform>
<Image.Style>
<Style>
<Style.Triggers>
<Trigger Property="Image.IsEnabled" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
From="0"
To="360"
Duration="0:0:1"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
How can I synchronise the animation, so that every circle is rotating with the same angle, regardless when it was started?
In my case it was enough to store Storyboards in a list. Every time when a animated icon was added I simply iterate through all Storyboards and started them again (sb.Begin()).
There is a small flicker, because every element is starting at the initial position, but they are running absolut synchronously.
Related
I've consulted a number of sources on rotating an image using the WPF's declarative XAML format, namely, this pretty solid blog post, Rotate an Image in WPF Using Just XAML, and an SO question: wpf rotate image around center.
As a result, my XAML - which is rotating the image - looks like this:
<UserControl.Resources>
<Style x:Key="Spinner" TargetType="Image">
<Setter Property="Image.RenderTransform">
<Setter.Value>
<RotateTransform CenterX="13" CenterY="13" />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="90"
To="360"
Duration="0:0:4"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
The problem I am having is that the rotation appears fluid and continuous, rather than by the 90 deg. specified by the By property. I am attempting to rotate a particular portion of the image to a particular quadrant on each animation.
The answer, https://stackoverflow.com/a/23699219/3469725, gets close to what I need; however, the image is rotated once and is not continuously animated.
Is this possible with WPF and is the By property the correct property to be using?
There is no To + By combination (at least for DoubleAnimation).
It's not really clear what you expect. You have initial value (e.g. 0) and you set Duration and To, which is enough to calculate how animation will change the angle value. By is meaningless disregards which value you will set.
If you need some kind of steps, then you have to do it with series of fast animations: rotate 90°, wait (or use easing function), rotate another 90°, etc.
<Storyboard RepeatBehavior="Forever" >
<DoubleAnimation To="90" Duration="0:0:1" ... >
<DoubleAnimation.EasingFunction>
<BounceEase Bounces="2" EasingMode="EaseOut" Bounciness="1.8" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
... more animations to rotate for 360 degrees if steps need different animation
... otherwise use `By` (without `To`) and repeat above animation it indefinitely
</Storyboard>
See for more about easing functions. Just try some until you understand how they work and find the best fitting for your animation.
I was approaching this in an entirely "wrong" way. Here is my solution which does not use the DoubleAnimation XAML property, but, rather, the DoubleAnimationUsingKeyFrames - an entirely different approach. For what I am attempting to do - rotate by 90 deg. intervals - this is a simple solution that does not require use of easing and gives more of a "snapping" effect.
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="RenderTransform.Angle"
Duration="0:0:4"
RepeatBehavior="Forever">
<DoubleKeyFrameCollection>
<DiscreteDoubleKeyFrame KeyTime="0:0:1" Value="90"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:2" Value="180"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:3" Value="270"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:4" Value="360"/>
</DoubleKeyFrameCollection>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
I would like to alter my program so that when an image is clicked it reveals a sidebar on the far right side of the application.
I have currently been trying to achieve this using an Expander. This is what it looks like so far:
<Expander>
<Expander.Header>
<Image Width="200" Height="300" Source="{Binding image}"/>
</Expander.Header>
<i:Interaction.Behaviors>
<local:UniqueNameBehavior ID="{Binding id}"/>
</i:Interaction.Behaviors>
<StackPanel Margin="10,4,0,0">
<ToggleButton Margin="4" Content="Option 1" Template="{StaticResource SimpleExpanderButtonTemp}"/>
<ListView>
<TextBox Text="Search" />
</ListView>
</StackPanel>
</Expander>
The idea is that whenever any movie is clicked, a sidebar on the far right side of the app is revealed containing info about the movie. If another movie is subsequently clicked, the sidebar will now contain info about the new movie.
I know that it is possible to change the ExpandDirection, but this only results in the content appearing beside the image as opposed to the far right of the application.
I've also tried adjusting the Margin of StackPanel but this results in the surrounding movies being pushed aside.
Could someone please help me out with how I can achieve this?
Thank you for your help!
I don't believe this kind of behaviour can be achieved using expanders the way you are using.
Why don't you create a grid on the far right side of your app with its width set to 0 and when you click/select a movie it sets the grid width to a new value and change its content based on the movie?
<Grid HorizontalAlignment="Right">
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Width" Value="0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ShowMovieForm}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Width" To="400" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Width" To="0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
I am trying to get an Ellipse to blink in case the icon inside another UserControl is Pause, and stop blinking if the icon is Play.
Here is the Ellipse and my attempt at binding to the PlayIcon.Opacity with a DataTrigger, which isn't working
<Ellipse.Style>
<Style TargetType="{x:Type Ellipse}">
<Style.Triggers>
<DataTrigger Binding="{Binding Opacity, Path=PlayIcon, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type views:PlayButton}}}" Value="0">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="0"
To="3"
RepeatBehavior="Forever"
AutoReverse="True"
Duration="0:0:0.1"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
<views:PlayButton />
Here is the Pause and Play Icons in the PlayButton UserControl
<UserControl x:Class="MyNamespace.PlayButton" ...>
...
<Path Name="PlayIcon" Fill="Blue" Opacity="0" Data="M18,12 18,38 35,25"/>
<Path Name="PauseIcon" Fill="Blue" Opacity="10" Data="M15,12 15,38 23,38 23,12z M27,12 27,38 35,38 35,12" />
...
</UserControl>
How can I make this DataTrigger fire when the Opacity of the Play Icon is 0, or if Pause icon Opacity is 10 inside the PlayButton UserControl?
I'm trying to create a text box, which would glow when focused.
All samples of how to do this I've seen so far were based on OuterGlowBitmapEffect , and it appears that it does not work in .net 4.
The recommendation in the second article is to use blur effect. I have no idea on how to use blur to get object's outer layer to glow without distorting the inner content of the object.
Ultimately, I'm hoping to create a text box, which would display glow up animation when focused, and the glow would slowly (1-2 seconds) fade after the control has lost focus.
Any ideas on what is the best way to do this in wpf 4.0?
You can try to get a decent "Glow-Effect" with DropShadowEffect. Here is an example
Update. A TextBox that starts to "glow" when focused and the "glow" slowly fades out for two seconds when it loses focus
<TextBox Text="Test">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect ShadowDepth="0"
Color="Gold"
Opacity="0"
BlurRadius="8"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1.0"
Storyboard.TargetProperty="(Effect).Opacity"
Duration="00:00:00"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="0.0"
Storyboard.TargetProperty="(Effect).Opacity"
Duration="00:00:02"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Take a look at
http://wpfthemes.codeplex.com/
for a lot of good wpf theme ideas. In particular, look at the theme for the textbox in Bureau Black. I think what you want is actually what they use for their 'mouseover' attribute, but it should be easy to change that to a focused property instead.
I have a problem with color animation. This is my source:
<Window.Resources>
<hedit:BrushToColorConverter x:Key="BrushToColorConverter" />
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Resources>
<Storyboard x:Key="buttonAnimIn">
<!-- Problem line -->
<ColorAnimation Storyboard.TargetName="bntBack" Storyboard.TargetProperty="Color" To="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource BrushToColorConverter}}" />
</Storyboard>
<Storyboard x:Key="buttonAnimOut">
<ColorAnimation Storyboard.TargetName="bntBack" Storyboard.TargetProperty="Color" To="Blue" />
</Storyboard>
<Storyboard x:Key="buttonAnimForegroundIn">
<ColorAnimation Storyboard.TargetName="btnFore" Storyboard.TargetProperty="Color" To="Blue" />
</Storyboard>
<Storyboard x:Key="buttonAnimForegroundOut">
<ColorAnimation Storyboard.TargetName="btnFore" Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</ControlTemplate.Resources>
<Border Name="border"
BorderThickness="1"
Padding="4,2"
BorderBrush="DarkGray"
CornerRadius="3">
<Border.Background>
<SolidColorBrush Color="Blue" x:Name="bntBack" />
</Border.Background>
<ContentControl HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}">
<ContentControl.Foreground>
<SolidColorBrush Color="Red" x:Name="btnFore" />
</ContentControl.Foreground>
</ContentControl >
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard Storyboard="{StaticResource buttonAnimIn}" />
<BeginStoryboard Storyboard="{StaticResource buttonAnimForegroundIn}" />
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard Storyboard="{StaticResource buttonAnimOut}" />
<BeginStoryboard Storyboard="{StaticResource buttonAnimForegroundOut}" />
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
The problem is:
Cannot convert the value in attribute 'Style' to object of type 'System.Windows.Style'. Cannot freeze this Storyboard timeline tree for use across threads. Error at object 'System.Windows.Controls.Button' in markup file 'HLSLEditor;component/mainwindow.xaml' Line 223 Position 25.
When using fixed colors it worked, but it cannot work with the Foreground color of the parent...
How do I do an animation to the foreground or background color?
Thanks!
You cannot freeze Bindings, you probably can get around this issue by declaring a color as a resource and then bind your Control's Background to it while using StaticResource in the animation.
e.g.
<Window.Background>
<SolidColorBrush Color="{DynamicResource Background}"/>
</Window.Background>
<Window.Resources>
<Color x:Key="Background">Green</Color>
</Window.Resources>
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
Duration="0:0:1"
To="{StaticResource Background}"/>
Alternative using a resource class:
public static class MyColors
{
public static Color MyHighlightColor = Color.FromArgb(255, 0, 88, 0);
}
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
Duration="0:0:1"
To="{x:Static local:MyColors.MyHighlightColor}"/>
I think that understanding the error might give you a way of fixing the problem.
Animation requires the use of threads besides the UI thread. So storyboards have to be freezable, which means that all the animations in the storyboard must be freezable, and everything those animations use must also be freezable.
Bindings aren't freezable - pretty much by definition, as they are a mechanism whereby a dependency property can be changed. You can't use a dynamic binding in a color animation - there's the possibility that the property could change while the animation was running. The same thing happens whether you're binding to an object or you're using DynamicResource.
The thing is, this is protecting you from something that you don't really want anyway. You don't really want the colors to change while the animation is running. That's not what you're trying to accomplish. You want the color resources that the animation is using to change if the user selects a different skin.
So instead of binding storyboards to skinnable resources, add the storyboards to the dictionary of resources that get set when the skin changes (using static bindings to set the colors), and use dynamic binding in your event triggers. That should work.
When I came across this problem I worked around it by modifying my style to contain two identical elements on top of each other - one for the 'normal' state and one for the 'pressed' state. The 'pressed' one had its Opacity set to 0 by default and the other one had an Opacity of 1. My animation changed the opacities from 0 to 1 and vice versa.
This approach avoided actually animating the Color property but produced the same effect whilst keeping everything in XAML. As the colours were set in the style definition rather than the animation they could be bound as required. This will probably not be suitable for all situations but for my fairly simple style it was a very quick way to achieve the desired effect.