如何在Silverlight 4中等待状态转换完成?

12

我需要改变一个控件的状态,然后执行一些操作。具体来说,我想在隐藏一个控件之前运行一个动画。我希望能够做到类似这样的效果:

VisualStateManager.GoToState(control, "Hidden", true); // wait until the transition animation is finished
ParentControl.Children.Remove(control);

问题在于过渡动画是异步运行的,因此控件在动画启动后立即从可视树中移除。

那么我该如何等待动画完成?


这在WPF中也适用。感谢您的帖子,这正是我正在寻找的! - Josh G
这个能用MVVM实现吗? - user20358
3个回答

14

您可以将Storyboard.Completed事件处理程序附加到Storyboard,或将VisualStateGroup.CurrentStateChanged事件处理程序附加到VisualStateGroup:

<UserControl
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" mc:Ignorable="d"
x:Class="SilverlightApplication7.MainPage"
Width="640" Height="480">

<Grid x:Name="LayoutRoot" Background="White">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="VisualStateGroup" >
            <VisualState x:Name="Hidden">
                <Storyboard Completed="OnHidden">
                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <Rectangle x:Name="rectangle" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="136" Margin="48,72,0,0" Opacity="0" Stroke="Black" VerticalAlignment="Top" Width="208"/>
</Grid>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightApplication7
{
public partial class MainPage : UserControl
{
    public MainPage()
    {
        // Required to initialize variables
        InitializeComponent();

        this.Loaded += new RoutedEventHandler(MainPage_Loaded);
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        VisualStateManager.GoToState(this, "Hidden", true);
    }

    private void OnHidden(object storyboard, EventArgs args)
    {

    }
}

}


这是一个HTML标签,它包含了一个右大括号字符 "}"。

这是我想到的唯一解决方案。但对我来说,它似乎不太好和干净。另一方面,如果没有其他解决方案,我将别无选择。谢谢。 - gius
但是如果我们正在使用自定义控件呢?在这种情况下,无法将处理程序添加到XAML中。 - Samvel Siradeghyan

3

实际上,在代码中可以附加Completed处理程序:

Collection<VisualStateGroup> grps = (Collection<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(this.LayoutRoot);
foreach (VisualStateGroup grp in grps) {
    Collection<VisualState> states = (Collection<VisualState>)grp.States;
    foreach (VisualState state in states) {
        switch (state.Name) {
            case "Intro":
            state.Storyboard.Completed += new EventHandler(Intro_Completed);break;
        }
    }
}

以下是一个来自该线程的示例:http://forums.silverlight.net/forums/p/38027/276746.aspx

在我使用附加行为工作时,它对我的实时项目有效!稍微有点烦人的是,我不得不为根UserControl(用于在VisualStateManager.GoToState中使用)和LayoutRoot使用单独的依赖属性,以获取实际的VisualStateGroup集合。


3

处理这个问题的正确方法是监听 VisualStateGroup 上的 CurrentStateChanged 事件,但根据我的经验,这种方式最好也不可靠,最坏的情况下会出现故障。

第二种选择是在您的 Storyboard 上挂接 Completed 事件,但这种选择也有自己的缺陷。在某些情况下,可视状态管理器会内部生成动画,因此您设置的 Completed 事件将不会被调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接