gpt4 book ai didi

c# - WPF 动画开始但显示太晚

转载 作者:太空狗 更新时间:2023-10-29 19:44:32 25 4
gpt4 key购买 nike

我正在使用 .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>

奇怪的是,当我在测试窗口中使用此控件并重复单击加载复选框(并且在动画完成之前)时,淡入/淡出动画确实按我预期的那样工作.

有人可以帮忙吗?提前致谢!

最佳答案

如果不查看其余代码,很难确切地看出问题出在哪里,但我猜测它与动画属性的起始值有关。

我在 WPF 中实现了一个自定义控件,在 View 框中有一个矩形,并使用问题中的触发器 + Storyboard来查看效果。事实上,我的第一次尝试既没有淡入也没有淡出。

我解决这个问题的方法是在动画中指定 From 值,这样无论 DP 的原始值是多少,它们都能正常工作:

<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
From="0"
To="1" />

注意上面动画中的 From="0"。最终 Storyboard以相同的方式修改,从 1 变为 0。

为了完整起见,我还在 ControlTemplate 内的 viewbox 元素的定义中将不透明度设置为 0


这里是相关部分的完整源代码。该控件是一个标准的 WPF 自定义控件,继承自 Control .它有一个名为 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 - 在 generic.xaml 中以 {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();
}

关于c# - WPF 动画开始但显示太晚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6135488/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com