WPF 在控件上淡出

Posted

技术标签:

【中文标题】WPF 在控件上淡出【英文标题】:WPF Fade Out on a control 【发布时间】:2011-05-18 02:26:10 【问题描述】:

在我的 WPF 应用程序中,我有一个反馈控件,希望在用户操作完成后显示(保存数据、删除...)。可见性设置为隐藏开始,样式设置为定义为资源的 animateFadeOut 样式(见下文)。然后我想在我的 C# 代码中将文本和控件 Visibility 设置为可见,并让反馈控件显示消息并在 5 秒后淡出并保持隐藏 (Visibility.Hidden)。

以下 XAML 在我第一次调用 control.Visiblity= Visibility.Visible 时有效,但该控件第二次没有重新出现。我认为这是因为动画仍在运行,它可以控制反馈控制。然后我尝试将 FillBehavior 设置为“停止”,但这只是使控件再次可见并且我希望它隐藏。然后,使用 FillBehavior="Stop",我尝试设置触发器“当不透明度 = 0 时,将可见性设置为隐藏”。触发器似乎没有触发,动画完成后我再次看到了可见控件。

请帮忙指出我在这里做错了什么。

或者,如果您能提出一种更好的方法来显示一个在 5 秒后消失并且可以反复调用的控件,我将不胜感激。

谢谢!

<Style TargetType="x:Type FrameworkElement" x:Key="animateFadeOut">
        <Style.Triggers>
            <Trigger Property="Visibility" Value="Visible">
                <Trigger.EnterActions>
                    <BeginStoryboard >
                        <Storyboard>
                            <DoubleAnimation BeginTime="0:0:5.0" Storyboard.TargetProperty="Opacity"
                         From="1.0" To="0.0" Duration="0:0:0.5"/>
                        </Storyboard>
                    </BeginStoryboard>             
                </Trigger.EnterActions>
            </Trigger>
        </Style.Triggers> 
    </Style>

【问题讨论】:

我采取了一种稍微不同的方法来解决这个问题......我用 C# 编写了它。 (见下面的帖子-评论部分太小,无法发布代码) 【参考方案1】:

问题是你的动画完成后你的控件仍然有Visibility=Visible,所以不能再次进入。 我宁愿使用动画来完成整个事情,首先显示控件,然后隐藏它。

<Storyboard x:Key="animate">
    <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetProperty="Visibility">
        <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
                <Visibility>Visible</Visibility>
            </DiscreteObjectKeyFrame.Value>
        </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
    <DoubleAnimation BeginTime="0:0:0.0" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.2"/>
    <DoubleAnimation BeginTime="0:0:5.0" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5"/>
    <ObjectAnimationUsingKeyFrames BeginTime="0:0:5.5" Storyboard.TargetProperty="Visibility">
        <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
                <Visibility>Hidden</Visibility>
            </DiscreteObjectKeyFrame.Value>
        </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
</Storyboard>

并按如下方式使用:

((Storyboard)FindResource("animate")).Begin(someControl);

【讨论】:

谢谢,阿尔法鼠标。您回答了我在下面发布给 Liz 的问题。另一个问题,一旦动画完成,不透明度=0.0 还是仅在动画中?我问是因为当我将 FillBehavior 设置为 Stop 时,不透明度恢复到 1.0。 @sondlerd:当 FillBehaviour 为 Stop 时,是的,the value of the property returns to it's original value 您可以通过将两个关键帧组合成同一个动画并定义枚举内联&lt;DiscreteObjectKeyFrame KeyTime="0:0:6.5" Value="x:Static Visibility.Hidden"/&gt;来缩短此时间以提高效率 当我开始寻找这个时,我发现了很多半答案和损坏的代码。所以我很欣赏这个优雅的解决方案。谢谢:)【参考方案2】:

Liz 关于可见性仍然可见是正确的。 alpha-mouse 也是正确的,您需要在某个时候将其设置回隐藏。但是如果你在动画完成之前将它设置回来,它就不起作用了:

MyControl.Visibility = System.Windows.Visibility.Visible;
MyControl.Visibility = System.Windows.Visibility.Hidden;

因为动画具有更高的优先级 (MSDN)

您可以在 Storyboard.Completed 事件中将其设置回隐藏:

private void Show()
    
        MyControl.Visibility = System.Windows.Visibility.Visible;

        var a = new DoubleAnimation
                    
                        From = 1.0,
                        To = 0.0,
                        FillBehavior= FillBehavior.Stop,
                        BeginTime = TimeSpan.FromSeconds(2),
                        Duration = new Duration(TimeSpan.FromSeconds(0.5))
                    ;
        var storyboard = new Storyboard();

        storyboard.Children.Add(a);
        Storyboard.SetTarget(a, MyControl);
        Storyboard.SetTargetProperty(a, new PropertyPath(OpacityProperty));
        storyboard.Completed += delegate  MyControl.Visibility = System.Windows.Visibility.Hidden; ;
        storyboard.Begin();            
    

【讨论】:

感谢 Kai,我似乎一直回到 C# 以在 WPF 中完成工作。我对 WPF 比较陌生(在 2007 年为它工作了 6 个月,然后在过去的三周为一个项目工作)。也许这只是学习曲线。感谢您指出 storyboard.Completed 事件。 @sondlerd:只要能把事情做好,我不介意用代码来做。事实上,在这种情况下,我认为在代码中做比在 xaml 中更清晰。【参考方案3】:

这是我的工作。这会使控件再次淡入和淡出。我没有玩弄可见性,而是只玩不透明度来处理它。

感谢本文中的 Kane 提供原始代码:Fade any control using a WPF animation

Storyboard storyboard = new Storyboard();
TimeSpan duration = TimeSpan.FromMilliseconds(500); //

DoubleAnimation fadeInAnimation = new DoubleAnimation() 
     From = 0.0, To = 1.0, Duration = new Duration(duration) ;

DoubleAnimation fadeOutAnimation = new DoubleAnimation()
     From = 1.0, To = 0.0, Duration = new Duration(duration) ;
fadeOutAnimation.BeginTime = TimeSpan.FromSeconds(5);

Storyboard.SetTargetName(fadeInAnimation, element.Name);
Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath("Opacity", 1));
storyboard.Children.Add(fadeInAnimation);
storyboard.Begin(element);

Storyboard.SetTargetName(fadeOutAnimation, element.Name);
Storyboard.SetTargetProperty(fadeOutAnimation, new PropertyPath("Opacity", 0));
storyboard.Children.Add(fadeOutAnimation);
storyboard.Begin(element);

【讨论】:

很好的例子。我尝试了不同的淡入/淡出动画解决方案,这个非常简单明了。【参考方案4】:

我的上帝,那是永远的。看看这个,它解决了使用 alpha 将 Visibility 更改为“Visible”和“Hidden”时动画的问题,并且动画不会冻结。

using System.Windows;

namespace WpfApplication4

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    
        public MainWindow()
        
            InitializeComponent();
        

        private void button1_Click(object sender, RoutedEventArgs e)
        
            button.Visibility = Visibility.Hidden;
        

        private void button2_Click(object sender, RoutedEventArgs e)
        
            button.Visibility = Visibility.Visible;
        
    

XAML:

<Window x:Class="WpfApplication4.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:WpfApplication4"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>

            <Style BasedOn="StaticResource x:Type Button" TargetType="x:Type Button">
                <Style.Resources>
                    <Storyboard x:Key="FadeOut">
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" FillBehavior="Stop">
                            <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="x:Static Visibility.Visible"/>
                            <DiscreteObjectKeyFrame KeyTime="0:0:1" Value="x:Static Visibility.Hidden"/>
                        </ObjectAnimationUsingKeyFrames>
                        <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:1" AutoReverse="False" />
                    </Storyboard>
                    <Storyboard x:Key="FadeIn">
                        <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:1" AutoReverse="False" />
                    </Storyboard>
                </Style.Resources>
                <Setter Property="Width" Value="120"></Setter>
                <Style.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="Visibility" Value="Hidden" />
                            <Condition Property="Opacity" Value="1" />
                        </MultiTrigger.Conditions>
                        <MultiTrigger.EnterActions>
                            <StopStoryboard BeginStoryboardName="FadeInStoryboard" />
                            <BeginStoryboard Name="FadeOutStoryboard" Storyboard="StaticResource FadeOut" />
                        </MultiTrigger.EnterActions>
                    </MultiTrigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="Visibility" Value="Visible" />
                            <Condition Property="Opacity" Value="0" />
                        </MultiTrigger.Conditions>
                        <MultiTrigger.EnterActions>
                            <StopStoryboard BeginStoryboardName="FadeOutStoryboard" />
                            <BeginStoryboard Name="FadeInStoryboard" Storyboard="StaticResource FadeIn" />
                        </MultiTrigger.EnterActions>
                    </MultiTrigger>
                </Style.Triggers>
            </Style>

        </Grid.Resources>
        <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="200,186,0,0" VerticalAlignment="Top" Width="75" Height="38" />
        <Button x:Name="button1" Content="Hide it" HorizontalAlignment="Left" Margin="112,96,0,0" VerticalAlignment="Top" Width="75" Click="button1_Click"/>
        <Button x:Name="button2" Content="Show it" HorizontalAlignment="Left" Margin="200,96,0,0" VerticalAlignment="Top" Width="75" Click="button2_Click"/>
        <Label x:Name="label" Content="Binding ElementName=button, Path=Opacity" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
        <Label x:Name="label1" Content="Binding ElementName=button, Path=Visibility" HorizontalAlignment="Left" Margin="10,36,0,0" VerticalAlignment="Top"/>

    </Grid>
</Window>

【讨论】:

【参考方案5】:

上面的所有答案都至少使用了某种 XAML 代码,我个人并不是很喜欢这些代码(因为它非常令人困惑),所以我找到了一种方法来使用一些简单的 C# 代码来做同样的事情:

int secs = 2; // How long the fade should take in seconds

for (int i = 99; i >= 0; i--)

    someControl.Opacity = i / 100d;

    await Task.Delay(secs * 10);


someControl.Visibility = Visibility.Hidden;

someControl.Opacity = 1;

您可以在任何Control 上使用它。您还需要在方法签名中添加 async 修饰符。如果没有 await 运算符,您的 UI 在控件淡出时无法响应。

控件淡出后,可以像这样让它再次可见:

someControl.Visibility = Visibility.Visible;

这种方法可能不是“最好的”,但肯定是最简单易懂的。

【讨论】:

【参考方案6】:

这应该可以修复您的故事板。

但是,请记住,一旦动画完成,您的控件将完全不透明 - 不可见,但您的 Visibility 属性仍设置为 Visible。因此,您必须确保 Visibility 属性在某处也被重置为隐藏或折叠。

<Style TargetType="x:Type FrameworkElement" x:Key="animateFadeOut">
         <Style.Triggers>
            <Trigger Property="Visibility" Value="Visible">
               <Trigger.EnterActions>
                  <BeginStoryboard Name="MyFadeEffect">
                     <Storyboard>
                        <DoubleAnimation BeginTime="0:0:5.0" Storyboard.TargetProperty="Opacity"
                         From="1.0" To="0.0" Duration="0:0:0.5"/>
                     </Storyboard>
                  </BeginStoryboard>
               </Trigger.EnterActions>
               <Trigger.ExitActions>
                  <StopStoryboard BeginStoryboardName="MyFadeEffect"/>
               </Trigger.ExitActions>
            </Trigger>
         </Style.Triggers>
      </Style>

【讨论】:

感谢您的快速回复。我可以在情节提要的末尾将 Visibility 设置为 Hidden 以解决您提出的问题,“您的 Visibility 属性仍设置为 Visible”吗? 不,我试过了,但是您不能更改用作触发器条件的属性的值。但是现在您知道如何停止动画了。 :)

以上是关于WPF 在控件上淡出的主要内容,如果未能解决你的问题,请参考以下文章

MPMoviePlayerController 添加 UIButton 以查看淡入淡出的控件

wpf中我想在WebBrowser控件上放置一个Border控件

WPF在控件里面嵌套WPF窗体

WPF在控件里面嵌套WPF窗体

在 WPF 的网格中显示对其他控件的控件

wpf 控件属性通过数据绑定到某个集合的某一个数据上。