Reputation: 75
I'm practicing using xaml styles by making a simple traffic light controlled by radiobuttons. However, my code crashes because there is a reference error using Canvas.Top in the Ellipse style. Is there any way I could fix that while keeping everything in the style and not in the Ellipse itself?
Here is my code:
<Window x:Class="hw05.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:hw05"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="Red"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=RedRB}" Value="True">
<Setter Property="Fill" Value="Red"></Setter>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Canvas.Top" Duration="0:0:0.400" To="83">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding IsChecked, ElementName=YellowRB}" Value="True">
<Setter Property="Fill" Value="Orange"></Setter>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Canvas.Top" Duration="0:0:0.400" To="133">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding IsChecked, ElementName=GreenRB}" Value="True">
<Setter Property="Fill" Value="Green"></Setter>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Canvas.Top" Duration="0:0:0.400" To="183">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Canvas>
<RadioButton Name="RedRB" GroupName="One" IsChecked="True" Canvas.Left="50" Canvas.Top="100">first</RadioButton>
<RadioButton Name="YellowRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="150">second</RadioButton>
<RadioButton Name="GreenRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="200">third</RadioButton>
<Ellipse Name="Light" Width="50" Height="50" Canvas.Left="180"></Ellipse>
</Canvas>
</Window>
EDIT included setter for a Canvas.Top value and used parentheses for (Canvas.Top):
<Window x:Class="hw05.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:hw05"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="Red"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=RedRB}" Value="True">
<Setter Property="Fill" Value="Red"></Setter>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Canvas.Top)" Duration="0:0:0.400" To="83">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding IsChecked, ElementName=YellowRB}" Value="True">
<Setter Property="Fill" Value="Orange"></Setter>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Canvas.Top)" Duration="0:0:0.400" To="133">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding IsChecked, ElementName=GreenRB}" Value="True">
<Setter Property="Fill" Value="Green"></Setter>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Canvas.Top)" Duration="0:0:0.400" To="183">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Canvas>
<RadioButton Name="RedRB" GroupName="One" IsChecked="True" Canvas.Left="50" Canvas.Top="100">first</RadioButton>
<RadioButton Name="YellowRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="150">second</RadioButton>
<RadioButton Name="GreenRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="200">third</RadioButton>
<Ellipse Name="Light" Width="50" Height="50" Canvas.Left="180" Canvas.Top="82"></Ellipse>
</Canvas>
</Window>
Upvotes: 0
Views: 213
Reputation: 169170
Canvas.Top
is an attached property so you should add parentheses around it:
Storyboard.TargetProperty="(Canvas.Top)"
You should also set the From
property of the DoubleAnimation
to a valid double
such as for example 0
:
<DoubleAnimation
Storyboard.TargetProperty="(Canvas.Top)" Duration="0:0:0.400" From="0" To="133">
Alternatively, you could set the Canvas.Top
property of the element being animated to an initial value:
<Ellipse Name="Light" Width="50" Height="50" Canvas.Top="10" Canvas.Left="180"></Ellipse>
Or add a Setter
to the Style
:
<Setter Property="Canvas.Top" Value="10"/>
Upvotes: 1
Reputation: 128062
When you animate a property without setting the animation's From
property, the animation starts from the current value of the property.
For Canvas.Top
and the other Canvas attached properties, the default value (and hence the current value) is double.NaN
, not 0
.
Just set an initial value by a Style Setter:
<Style TargetType="Ellipse">
<Setter Property="Canvas.Top" Value="0"/>
...
</Style>
Or directly on the Ellipse:
<Ellipse Canvas.Top="0" .../>
You would also need to use the correct animated property path for attached properties, which uses parentheses:
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" .../>
Upvotes: 1