我正在WPF
创建一个自定义控件,实际上是AnalogClock
。这是一个非常简单的类,其模板如下所示:
public class AnalogClock {
public static readonly DependencyProperty AnimatorProperty
= DependencyProperty.Register("Animator", typeof(Storyboard), typeof(AnalogClock),
new FrameworkPropertyMetadata(null));
public Storyboard Animator {
get { return (Storyboard)GetValue(AnimatorProperty); }
set { SetValue(AnimatorProperty, value); }
}
public override void OnApplyTemplate() {
base.OnApplyTemplate();
if (Animator == null)
return;
ApplyTargetToTimeline("PART_HourHandAnimator", "PART_HourHand");
ApplyTargetToTimeline("PART_MinuteHandAnimator", "PART_MinuteHand");
ApplyTargetToTimeline("PART_SecondHandAnimator", "PART_SecondHand");
ApplyTargetToTimeline("PART_IconAnimator", "PART_Icon");
Animator.Begin(this, Template);
// try to seek the timeline, to DateTime.Now.TimeOfDay
// but can not ):
Animator.Seek(this, DateTime.Now.TimeOfDay, TimeSeekOrigin.Duration);
}
private void ApplyTargetToTimeline(string timelineName, string targetName) {
var timeline = Animator.Children.FirstOrDefault(t => t.Name == timelineName);
if (timeline == null)
throw new InvalidOperationException(string.Format(
"The Timeline named '{0}' could not be found.", timelineName));
Storyboard.SetTargetName(timeline, targetName);
}
}
这是XAML
:
故事板资源:
<Storyboard x:Key="Animator">
<DoubleAnimation x:Name="PART_HourHandAnimator" From="0" To="360" Duration="12:00:00" BeginTime="00:00:00.000000"
RepeatBehavior="Forever" Storyboard.TargetName="{Binding}" Storyboard.Target="{Binding}"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"/>
<DoubleAnimation x:Name="PART_MinuteHandAnimator" From="0" To="360" Duration="1:00:00" BeginTime="00:00:00.000000"
RepeatBehavior="Forever" Storyboard.TargetName="{Binding}" Storyboard.Target="{Binding}"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"/>
<DoubleAnimation x:Name="PART_SecondHandAnimator" From="0" To="360" Duration="00:01:00" BeginTime="00:00:00.000000"
RepeatBehavior="Forever" Storyboard.TargetName="{Binding}" Storyboard.Target="{Binding}"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"/>
<DoubleAnimation x:Name="PART_IconAnimator" From="0" To="360" Duration="00:01:00" BeginTime="00:00:00.000000"
RepeatBehavior="Forever" Storyboard.TargetName="{Binding}" Storyboard.Target="{Binding}"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"/>
</Storyboard>
模板:
<ControlTemplate x:Key="MyTemplate" TargetType="{x:Type ui:AnalogClock}">
<Border>
<Viewbox>
<Grid>
<Ellipse x:Name="PART_Icon" >
<Ellipse.RenderTransform>
<RotateTransform CenterX="25" CenterY="25" />
</Ellipse.RenderTransform>
</Ellipse>
<Grid>
<Canvas x:Name="PART_SecondHand">
<Ellipse RenderTransformOrigin="0.5,0.5"/>
<Canvas.RenderTransform>
<RotateTransform CenterX="60" CenterY="60"/>
</Canvas.RenderTransform>
</Canvas>
<Canvas>
<Path x:Name="PART_HourHand" Fill="SomeBrush"
Data="Some data" RenderTransformOrigin="0.493,0.933">
<Path.RenderTransform>
<RotateTransform />
</Path.RenderTransform>
</Path>
<Path x:Name="PART_MinuteHand" Fill="Some brush"
Data="Some Data" RenderTransformOrigin="0.493,0.933">
<Path.RenderTransform>
<RotateTransform />
</Path.RenderTransform>
</Path>
</Canvas>
</Grid>
</Grid>
</Viewbox>
</Border>
</ControlTemplate>
风格:
<Style x:Key="MyClock" TargetType="{x:Type ui:AnalogClock}">
<Setter Property="Animator" Value="{StaticResource Animator}"/>
<Setter Property="Template" Value="{StaticResource MyTemplate}"/>
</Style>
正如你所看到的,这是一个非常简单的控制。好吧,它工作得很好,除了storyboard.Seek
方法根本不影响。我的意思是,控件显示得很好,动画开始和我想要的一样,但是从零时间开始);我希望我能把所有时间表的位置都带到DateTime.Now.TimeOfDay
,但我不能。我尝试了TimeSeekOrigin.Duration
和TimeSeekOrigin.BeginTime
。但它们都不起作用。你能帮忙找到问题吗?提前致谢。
答案 0 :(得分:1)
最后,我很幸运:)首先,当我们在Storyboard
上开始Template
时,不需要设置目标名称。其次,要使Storyboard.Seek
生效,我们应该使用isControllable = true
参数开始故事板。一起:
<Storyboard x:Key="Animator">
<DoubleAnimation From="0" To="360" Duration="12:00:00"
RepeatBehavior="Forever" Storyboard.TargetName="PART_HourHand"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"/>
<DoubleAnimation From="0" To="360" Duration="1:00:00"
RepeatBehavior="Forever" Storyboard.TargetName="PART_MinuteHand"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"/>
<DoubleAnimation From="0" To="360" Duration="00:01:00"
RepeatBehavior="Forever" Storyboard.TargetName="PART_SecondHand"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"/>
<DoubleAnimation From="0" To="360" Duration="00:01:00"
RepeatBehavior="Forever" Storyboard.TargetName="PART_Icon"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"/>
</Storyboard>
初学者代码:
public override void OnApplyTemplate() {
base.OnApplyTemplate();
if (Animator == null)
return;
// begin the storyboard on `this` control with its own `Template` and controllable
Animator.Begin(this, Template, true);
// the storyboard has a duration of Forever -as you can see, we did not specified any duration. Is this a default behavior?
// while the storyboard has a duration of Forever, we have to set seekOrigin to BeginTime
Animator.Seek(this, DateTime.Now.TimeOfDay, TimeSeekOrigin.BeginTime);
}