我正在使用.Net 4.0构建一些WPF控件。其中一个名为LoadingPane的控件是从ContentControl派生的自定义控件。 此LoadingPane控件的唯一作用是当IsLoading属性设置为true时,在其包含的内容上显示半透明层。 当IsLoading值改变时,我使用一些动画来淡入淡出。 当显示叠加层时,动画会旋转一圈椭圆。
到目前为止,这么好。一切都很好。但这是我的问题:当我将Loading属性设置为true时,动画不会直接显示。大概需要半秒钟。此时淡入动画已经运行,因此不透明度一步有效地从0变为1。
这是我的动画代码:
<ControlTemplate.Triggers>
<Trigger Property="IsLoading"
Value="True">
<Trigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="EndAnimateLoadingCanvas" />
<BeginStoryboard Name="AnimateLoadingCanvas">
<Storyboard FillBehavior="Stop">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
To="1" />
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:02"
Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
From="360"
To="0"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="AnimateLoadingCanvas" />
<BeginStoryboard Name="EndAnimateLoadingCanvas">
<Storyboard FillBehavior="Stop">
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
To="0" />
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
奇怪的是,当我在测试窗口中使用此控件并且我反复单击“加载”复选框(并且在动画完成之前),然后淡入/淡出动画确实有效,因为我希望它能够工作
有人可以帮忙吗? Thanx提前!
答案 0 :(得分:3)
如果没有看到剩下的代码,很难确切地知道问题是什么,但我的猜测是它与动画属性的起始值有关。
我在WPF中实现了一个自定义控件,在视图框中有一个矩形,并使用问题中的触发器+故事板来查看效果。实际上,我的第一次尝试并没有淡出或淡出。
我要解决的问题是在动画中指定From
值,这样无论DP的原始值是什么,它们都能正常工作:
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
From="0"
To="1" />
在上面的动画中注意From="0"
。最终的故事板以相同的方式进行了修改,从1变为0。
为了完整性,我还在ControlTemplate中的viewbox元素的定义上将不透明度设置为0
。
以下是相关部分的完整源代码。该控件是继承自Control的标准WPF自定义控件。它有一个名为IsLoading
(bool
)的依赖属性,默认为false
:
public bool IsLoading
{
get { return (bool)GetValue(IsLoadingProperty); }
set { SetValue(IsLoadingProperty, value); }
}
// Using a DependencyProperty as the backing store for IsLoading. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsLoadingProperty =
DependencyProperty.Register("IsLoading", typeof(bool), typeof(LoadingControl), new UIPropertyMetadata(false));
ControlTemplate - 在{x:Type local:LoadingControl}
<ControlTemplate TargetType="{x:Type local:LoadingControl}">
<ControlTemplate.Triggers>
<Trigger Property="IsLoading" Value="True">
<Trigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="EndAnimateLoadingCanvas" />
<BeginStoryboard Name="AnimateLoadingCanvas">
<Storyboard FillBehavior="Stop">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
From="0"
To="1" />
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:02"
Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
From="360"
To="0"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="AnimateLoadingCanvas" />
<BeginStoryboard Name="EndAnimateLoadingCanvas">
<Storyboard FillBehavior="Stop">
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
From="1"
To="0" />
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Viewbox x:Name="MyViewBoxje" Opacity="0">
<!-- BG with 0x50 alpha so that it's translucent event at 100% visibility -->
<Grid Width="100" Height="100" Background="#50000000">
<Rectangle Width="70" Height="20" Fill="Green" Stroke="Black" StrokeThickness="2" RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<RotateTransform Angle="360" x:Name="AnimatedRotateTransform" />
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
</Viewbox>
</Border>
</ControlTemplate>
我在主窗口中使用过这样的话:
<Grid x:Name="LayoutRoot">
<!-- All other stuff here ... -->
<my:LoadingControl IsLoading="{Binding IsLoading}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
为了测试它,我有一个ViewModel,其属性IsLoading
被设置为主窗口的DataContext。在ViewModel的构造函数中,我将IsLoading
设置为true,然后启动一个计时器,每隔5秒切换一次该属性的值:
public MainWindowViewModel()
{
IsLoading = true;
DispatcherTimer t = new DispatcherTimer();
t.Interval = TimeSpan.FromSeconds(5);
t.Tick += (s, e) => IsLoading = !IsLoading;
t.Start();
}
答案 1 :(得分:0)
在阅读了Isak的回答后,我终于明白了。 很抱歉,他的回答对我的案子没有帮助,但他让我朝着正确的方向前进。
第一次淡入似乎不起作用的原因是因为我的包含视图的可见性设置为在整个淡入动画执行时折叠。 这是由ObjectAnimationUsingKeyFrames引起的:
DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
没有指定持续时间,指定的单个关键帧动画太晚了。
添加
Duration="00:00:00"
解决了我的问题。
感谢大家的帮助!