I got my animation to work triggered by a property in my ViewModel. If I set my TargetProperty to Width, the below code actually works in growing the image.
Next, I wanted to actually move the image up and down. To do this, I added a Canvas component around my image, to be able to animate based on Canvas.Top property. Setting Canvas.Top on the image moves it where I want.
However, if I set my StoryBoard.TargetProperty to Canvas.Top, I get an error:
Cannot resolve all property references in the property path
Canvas.Top.
<Style x:Key="LoadingImageAnimation" TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsLoading}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="10" To="250" AutoReverse="True" Duration="0:0:30"
Storyboard.TargetProperty="Canvas.Top"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
Is my approach totally off, or just a matter of finding the Attached Property?
Did some digging around on Property Path Syntax, and the solution was actually simple. Needed to add parentheses:
Storyboard.TargetProperty="(Canvas.Top)"
The animation is not as smooth as i would like.. but at least it works now.
Related
This question already has an answer here:
: 'Cannot animate 'Fill.Color' on an immutable object instance.'
(1 answer)
Closed 2 years ago.
I am new to WPF, I Have a rectangle that I try to animate to flesh red color if some boolean is true. and I want it to stop when the boolean is false. In order to do that, I used the <DataTrigger.ExitActions>
However, I still want my Fill color to change according to the AlertColor, but after the animation is stopped it seems like the binding is stoped also, and the background-color stays LightPink only.
why? how can I fix this and is there a better approach to animate the color only in case of a specific color and stop the animation when the color changes (with Binding)?
The XAML relevant code:
<Rectangle Width="840" Height="40">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Fill">
<Setter.Value>
<SolidColorBrush Color="{Binding AlertUnit.AlertColor , FallbackValue=LightPink}"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding AlertUnit.Emergency}" Value="true" >
<DataTrigger.EnterActions>
<BeginStoryboard Name="FlashingRedAnimation">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Fill.Color" To="White" Duration="0:0:1" AutoReverse="True"
RepeatBehavior="Forever"></ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="FlashingRedAnimation" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
edit:
I found the problem it was a really silly one. the binding should be:
Binding AlertUnit.AlertColor.Color
not:
Binding AlertUnit.AlertColor
Thank you all for the help.
I produced a similar visual effect by animating the opacitity value of a brush rather than the colour.
<Style TargetType="{x:Type vctrl:perBlinkingBorder}">
<Style.Triggers>
<Trigger Property="IsBlinking" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard TargetProperty="(BlinkingBorderBrush).Opacity">
<DoubleAnimation
AutoReverse="True"
RepeatBehavior="Forever"
From="1"
To="0"
Duration="0:0:0.5">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
To ensure that the visual effect is removed, I have two brush properties on the perBlinkingBorder control, and switch between them when the IsBlinking property is set.
More details and a demo project on my recent blog post.
I found the problem it was a really silly one.
the binding should be:
Binding AlertUnit.AlertColor.Color
not:
Binding AlertUnit.AlertColor
Thank you all for the help.
I have a TabControl with dynamically created TabItems that each contain a Border element that I need to animate (make the border flash Yellow to orange) when a property on a viewmodel is greater than zero, via Data Binding, but remain black if the value is zero. Each TabItem has it's own instance of the viewmodel, so the property value could be different for each TabItem, therefore the animation should only be activated on the appropriate TabItem (i.e. each TabItem is a UserControl that contains several Border elements, one of which I wish to animate triggered by a Property value in the UserControls viewmodel).
I have several similar elements, so I am using a MultiDataTrigger to check for a tag on the element, as well as check the property value (via a converter).
I can successfully animate the BorderBrush when selecting a TabItem where the property value is greater than zero, but when I then select a TabItem where the property value is equal to zero, the animation should stop, but does not. I am also changing the BorderThickness and the Margin, and these settings return to the normal settings as expected, but the animation does not stop.
I am using a Style.Trigger to apply the animation, and a converter to convert the property's value from an int to a boolean (true if greater than zero, and false if zero).
Here is my xaml code (from app.xaml):
<Style TargetType="{x:Type Border}" x:Key="JobFilterExternalBorder">
<Setter Property="BorderThickness" Value="3"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="CornerRadius" Value="3"/>
<Setter Property="Margin" Value="2,0,1,0.8"/>
<Style.Triggers>
<!-- Add Data Trigger to identify if filter is UnprocessedParts and value is > 0, and animate border to imitate a flashing border -->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Tag}" Value="IsUnprocessed"/>
<Condition Binding="{Binding UnprocessedQty, Converter={StaticResource ConvertNonZeroToBoolean}}" Value="true"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="BorderThickness" Value="6"/>
<Setter Property="Margin" Value="0,-2,-1,-1.2"/>
</MultiDataTrigger.Setters>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Name="FlashStoryboard" Storyboard="{StaticResource AnimationFlashYellowToOrange}">
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="FlashStoryBoard" />
<RemoveStoryboard BeginStoryboardName="FlashStoryBoard"/>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
And my Storyboard:
<Storyboard x:Key="AnimationFlashYellowToOrange" Storyboard.TargetProperty="BorderBrush" RepeatBehavior="Forever" Duration="0:0:1" FillBehavior="Stop">
<ObjectAnimationUsingKeyFrames>
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="Yellow" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="Orange" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
And the view to which this is being applied:
<Border Name="UnprocessedQtyBorder" Tag="IsUnprocessed" Style="{StaticResource JobFilterExternalBorder}" >
</Border>
I can confirm that the MultiDataTrigger is working fine because the BorderThickness and changes back to the normal thickness when the MultiDataTrigger becomes false when selecting a TabItem where the property value is equal to zero. It's just the animation that does not stop.
I have tried:
Adding StopStoryboard to the MultiDataTrigger.ExitActions
Adding RemoveStoryboard to the MultiDataTrigger.ExitActions
Including FillBehaviour="Stop"
Adding a second MultiDataTrigger to start a new Storyboard that sets the BorderBrush to black
Changing the order of the Style settings to have the MultiDataTrigger before the standard property settings
Searching the internet for any other examples that might point me in the right direction
I need to have the Storyboard animate the border continuously while the offending element is on screen, so I have included the RepeatBehavior="Forever" property
I am following MVVM design pattern and would prefer to avoid having code-behind, but I'm not zealous about it.
I have been struggling with this all day and have not made any progress, so this is my last hope.
EDIT:
I suspect the MultiDataTrigger.ExitActions are never executed in order to stop the Storyboard, so an additional question must be asked; Is it even possible to stop a Storyboard in this manner? Can the MultiDataTrigger.ExitActions be triggered to execute some other way?
EDIT2:
I have created a sample VS solution to demonstrate the effect I am seeing. The solution can be found on GitHub here
EDIT3:
This is what is currently happening:
When returning to "Tab 1", the animation should stop.
I am trying to understand how animation works in WPF with StoryBoards.
So far I have managed the following :
creating a ListView with custom items and resources binding ;
using ItemContainerStyle in order to make sure each item takes all the width of the ListView ;
using EventTrigger to trigger specific animation
My problem is simple.
First I tried the Loaded trigger to animate an item whenever it is added to the ListView's binded ObservableCollection. It works fine with opacityproperty but the problem is that this event is triggered everytime I scroll, meaning Windows loads and unloads items on-the-go to save up memory (which is understable but uses a lot more CPU with complex item).
So it's a no go.
Furthermore, the Unloaded trigger "does not really work" and was solved here : https://stackoverflow.com/a/14619637/3535408
So, using the aforementioned solution, I would like to fire the animation manually.
To be more precise, whenever a specific property of my items (much like Removing) is changed, I'd like a StoryBoard to be started.
How to accomplish this for sliding animation ? Because I would really like to have my items to slide, on the X axis, in and out (entering via the left, and leaving via the left) of my ListView.
These sliding animations must be triggered only when an item is added to the binded ObservableCollection and when it is removed.
The following XAML code does not work :
Within a ListView > ListView.ItemTemplate > DataTemplate > DataTemplate.Triggers
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Removing}" Value="true" >
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard >
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5"/>
<DoubleAnimation Storyboard.TargetProperty="LayoutTransform.ScaleY" From="0" Duration="0:0:.2"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</DataTemplate.Triggers>
The opacity animation really works just fine. However the LayoutTransform produces the following System.InvalidOperationException : Cannot resolve all property references in the property path 'LayoutTransform.ScaleY'. Verify that applicable objects support the properties.
Moreover, I just do not know how to do a sliding animation on the X axis :/
Here is the content of my ListView'sItemContainerStyle :
<Setter Property="HorizontalAlignment" Value="Stretch"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
<Setter Property="Margin" Value="0, -2, 0, -2" ></Setter>
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform x:Name="transform" />
</Setter.Value>
</Setter>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform/>
</Setter.Value>
</Setter>
Thanks for the help
At the moment, I'm doing some experimentation. My current scenario: I have a StoryBoard to transition between 2 UserControls (for example, it shrinks the current UserControl then grows the other).
What I want to do is to have 2 UserControls defined as part of the XAML, with keys of "Current" and "Next". The Current should be bound to the currently viewed UserControl. The Next should be bound before transition, so the StoryBoard knows which element to transition to. Here's where I'm stuck: ENTIRELY using XAML, how would one go about this?
I have a simple StoryBoard that is a Resource of the ItemsControl, as well as two UserControl items:
<ItemsControl.Resources>
<Storyboard x:Key="TransitionStoryboard">
<!-- Shrink this one. -->
<DoubleAnimation Storyboard.Target="{Binding Current}" Storyboard.TargetProperty="Width" To="0" Duration="0:0:1"/>
<!--Grow the next.-->
<DoubleAnimation Storyboard.Target="{Binding Next}" Storyboard.TargetProperty="Width" To="100" BeginTime="0:0:1" Duration="0:0:1"/>
</Storyboard>
<UserControl x:Key="Current"/>
<UserControl x:Key="Next" Width="0"/>
</ItemsControl.Resources>
So, when I define a new UserControl that belongs to the ItemsControl (like this):
<my:Control1 x:Name="ControlOne"/>
How do I set the "Current" UserControl top be ControlOne? Then, when I want to transition, how do I set one as "Next"? And how can I change these after a trigger?
Thanks
This is a total mess. You seem to completely misunderstand on how the static resources are used.
To achieve what you are trying to do, you should first decide on what will trigger the animation. Ideally it should be some DependencyProperty on your controls, or a property on your view model (which implements INotifyPropertyChanged). For example, you can declare an IsSelected property. Then you should create a style which triggers "grow" animation when control is selected and triggers "shrink" animation, when control loses selection.
For example:
<Style TargetType="Control" x:Key="FancyStyle">
<Style.Triggers>
<DataTrigger Binding={Binding IsSelected} Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource YourGrowAnim}"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource YourShrinkAnim}"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
Then you should assign that style to every control, you want animated this way and set up transitions between IsSelected properties. You can also use EventTrigger instead and bind animations to events (for example you can trigger those animations when control gets/loses focus).
You should also fix your "grow" animation, it wont work, most likely.
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.