WPF ColorAnimation inside Window.Resources - wpf

I have a TextBlock that I would like to give it a color animation effect; I have done something like this:
<Window.Resources>
<Storyboard x:Key="AnimateTarget" RepeatBehavior="Forever">
<ColorAnimation AutoReverse="False" Duration="0:0:5" From="Red" To="black" Storyboard.TargetName="txtBarcode" AccelerationRatio="1" Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)" FillBehavior="HoldEnd">
</ColorAnimation>
</Storyboard>
</Window.Resources>
I start the animation from code behind:
((Storyboard)this.Resources["AnimateTarget"]).Begin();
but when i start the animation its give me the following error:
'Background' property does not point to a DependencyObject in path '(0).(1)'.
I would priciest if someone helps me on this,
Thanks,

Give your TextBlock any Background and it will work.
<TextBlock Name="txtBarcode"
Background="Transparent"
Probably Background is Null and so there is no DependencyObject to animate.

Related

Cannot resolve all property references in the propertypath

I have a UserControl with a Border, the color of the border should be setted with a Dependency Property. I also want to animate the opacity of the border. My current xaml code looks like this:
<Border BorderBrush="{Binding ElementName=ImageViewerUserControl,
Path=NotificationColor}" BorderThickness="3" x:Name="AnimatedBorderBrush"
Visibility="{Binding ElementName=ImageViewerUserControl,
Path=ShowSequenceErrorNotification, Converter={StaticResource boolToVisibility}}">
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="AnimatedBorderBrush"
Storyboard.TargetProperty="BorderBrush.Opacity"
RepeatBehavior="Forever"
AutoReverse="True"
From="1"
To="0.0"
Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>
This only give the error:
Cannot resolve all property references in the property path 'BorderBrush.Opacity'. Verify that applicable objects support the properties.
But if I change to color of the BorderBrush to, lets say Black it works. How is this possible to achieve? I want to set the Brush color of my border via a dependency property. And yes, the dependency property is a Brush
I think the problem here is that the animation will only work if there is an object (the Brush) to animate. If you register your DependencyProperty without a default value it is null by default. Please try registering the DP with a default value
public static readonly DependencyProperty NotificationColorProperty = DependencyProperty.Register(
"NotificationColor",
typeof(Brush),
typeof(ImageViewerUserControl),
new PropertyMetadata(Brushes.Transparent)
);
Edit:
And as #Sheridan says use Storyboard.TargetProperty="Opacity" instead of Border.Opacity. Although it works if you specify a direct BorderBrush it doesn't worked for me with a bounded DP.
Your AnimatedBorderBrush name is misleading as it relates to a Border and not a BorderBrush. If you want to animate the Border.Opacity, then use Border.Opacity in the DoubleAnimation instead of BorderBrush.Opacity:
<DoubleAnimation Storyboard.TargetName="AnimatedBorderBrush"
Storyboard.TargetProperty="Border.Opacity"
RepeatBehavior="Forever"
AutoReverse="True"
From="1"
To="0.0"
Duration="0:0:1" />
UPDATE >>>
Ahhhhh, my bad... As the animation is defined inside the Border, there is no need to reference it, just use Opacity:
<DoubleAnimation Storyboard.TargetName="AnimatedBorderBrush"
Storyboard.TargetProperty="Opacity"
RepeatBehavior="Forever"
AutoReverse="True"
From="1"
To="0.0"
Duration="0:0:1" />

EventTrigger on a TextBlock that sets a Border - Cannot resolve all property references

I have a Custom control in WPF in which I define a large ItemsControl Template.
In there, I have a Grid and in one column of that grid, I got a TextBlock and in another column I have a Border.
I want to highlight the Border when the mouse enters the TextBlock.
I tried several scenarios:
first an EventTrigger in the TextBlock's Style, but I learned that you can't do that, then an EventTrigger within the TextBlock's Triggers section, and now I just put it in the DataTemplate.Triggers of my ItemsControl, but I keep getting the error:
"Cannot resolve all property references in the property path 'Border.BorderBrush.Color'. Verify that applicable objects support the properties."
Here is the code that causes trouble:
<DataTemplate.Triggers>
<EventTrigger SourceName="mytxtblock" RoutedEvent="TextBlock.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="myborder"
Storyboard.TargetProperty="Border.BorderBrush.Color"
Duration="0:0:1"
To="White" />
<ThicknessAnimation Storyboard.TargetProperty="Border.BorderThickness"
Duration="0:0:1"
From="0"
To="1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</DataTemplate.Triggers>
I think I'm missing something about the way i refer to the Color property of my Border, any insight?
Thanks!
EDIT: I figured out that declaring a SolidColorBrush in Resources and then using that value allows me to get rid of the
Storyboard.TargetProperty="Border.BorderBrush.Color" that changes to Storyboard.TargetProperty="Border.BorderBrush",
but now the compiler tells me that the color i declared (i tried Green and Transparent) is not a valid value for "To"...
Try
<ColorAnimation
Storyboard.TargetName="myborder"
Storyboard.TargetProperty="BorderBrush.(SolidColorBrush.Color)"
Duration="0:0:1"
To="White" />
but you have to declare a BorderBrush
BorderBrush="whatever"
or
<Border.BorderBrush>
<SolidColorBrush Color="whatever" />
</Border.BorderBrush>
in your "myborder" too.
On your ColorAnimation there are two properties:
Storyboard.TargetName="myborder"
Storyboard.TargetProperty="Border.BorderBrush.Color"
It implies, that myborder has a property called Border. I think that causes your error.

WPF VisualStateManager Animation Binding

I'm using a simple DoubleAnimation in Button.Trigger. Animation From is bound to root element ActualHeight. This works as expected.
Next I've tried to move the Storyboard to VisualStateManager. Now WPF complains:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=ActualWidth; DataItem=null; target element is 'DoubleAnimation' (HashCode=29201322); target property is 'To' (type 'Nullable`1')
Is it not possible to use bindings in animations within the VisualStateManager.VisualStateGroups/VisualState ?
It seems not. I fixed the problem by moving the storyboard to resources. So now GameToTitle will work while TitleToGame will fail.
I'd still appreciate to know if this is expected or not.
Relevant XAML:
<Grid x:Name="MainInterface">
<Grid.Resources>
<Storyboard x:Key="GameToTitle">
<DoubleAnimation Storyboard.TargetName="GameScreenInterface" Storyboard.TargetProperty="(Control.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)" From="0" To="{Binding Path=ActualHeight, ElementName=MainInterface}" Duration="0:0:0.2"/>
<DoubleAnimation Storyboard.TargetName="TitleScreenInterface" Storyboard.TargetProperty="(Control.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)" From="{Binding Path=ActualHeight, ElementName=MainInterface, Converter={Converters:InverseConverter}}" To="0" Duration="0:0:0.2"/>
</Storyboard>
</Grid.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="TitleScreenState" Storyboard="{StaticResource ResourceKey=GameToTitle}"/>
<VisualState x:Name="GameScreenState">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="GameScreenInterface" Storyboard.TargetProperty="(Control.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)" From="{Binding Path=ActualHeight, ElementName=MainInterface}" To="0" Duration="0:0:0.2"/>
<DoubleAnimation Storyboard.TargetName="TitleScreenInterface" Storyboard.TargetProperty="(Control.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)" From="0" To="{Binding Path=ActualHeight, ElementName=MainInterface, Converter={Converters:InverseConverter}}" Duration="0:0:0.2"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<View:TitleScreen x:Name="TitleScreenInterface"/>
<View:GameScreen x:Name="GameScreenInterface" />
</Grid>
As the question's comments note, Storyboards containing bindings must be declared as resources instead of inline within the VisualStateGroup for the bindings to work. This is due to the fact that VisualStates aren't part of the VisualTree. Resources, on the other hand, are.
You can visualize this for yourself by using Snoop (or similar utility) to look at the visual tree of your application. You'll notice that Resources nodes appear in the visual tree within Snoop, but VisualStates do not.

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.

Binding a Storyboard property relative to the target of the storyboard

I have a storyboard which targets an element, and binds one of its own properties to a property on another element:
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.X"
From="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}"
To="0"
Duration="0:0:5"/>
</Storyboard>
This storyboard works when the storyboard is stored in the resources of the window which holds the storyboard target. The 'From' value is correctly bound to the ActualWidth of the host Window instance.
However, I need to store the storyboard in my application level resources. From here, the storyboard does not seem to be able to target the window to determine the 'From' property. This is understandable as from inside <Application.Resources>, the binding won't be able to find an 'ancestor' of type Window.
I guess I need to be able to bind the 'From' value, relative to the target of the animation, rather than relative to the storyboard's DoubleAnimation.
Is this possible, and if so, how?
Here is the sample MainWindow.xaml:
<Window.Resources>
<!--This works : Storyboard correctly sets 'From' property to 'ActualWidth' of window-->
<Storyboard x:Key="localStoryBoard">
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.X"
From="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}"
To="0"
Duration="0:0:5"/>
</Storyboard>
</Window.Resources>
<StackPanel>
<Button
RenderTransformOrigin="0,1"
HorizontalAlignment="Left"
Content="Click me">
<Button.RenderTransform>
<TranslateTransform/>
</Button.RenderTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource centralStoryBoard}"/>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
And here is an example app.xaml:
<Application x:Class="WpfApplication3.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<!--Storyboard doesn't work at all-->
<Storyboard x:Key="centralStoryBoard">
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.X"
From="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}"
To="0"
Duration="0:0:5"/>
</Storyboard>
</Application.Resources>
</Application>
This won't work, as the eventtrigger refers to the app.xaml version. If you change it to the local resource version, you can see it works.
The example doesn't work because when you put your storyboard to resources it has no Window ancestor. What actually RelativeSource do is search element tree backwards waiting for the node with AncestorType appear and then binds it.
When put in the Window.Resources there's actual Window back in the tree and it binds it correctly. When put to the application resources there's no Window back in the tree because it's not connected to the Window whatsoever.
If you really want to put your storyboard to the application resources you should consider giving up the idea with binding. Instead, you can check out this answer with code for a clipper, I think this is what you need - https://stackoverflow.com/a/59376318/11178539.

Resources