【问题标题】:How do I allow a storyboard to play before completing Tapped event?在完成 Tapped 事件之前,如何让故事板播放?
【发布时间】:2015-03-01 00:30:28
【问题描述】:

我正在构建一个本质上是一个按钮的用户控件(WinRT 8.1 通用应用程序)。您点击按钮,它会动画,然后处理程序执行开发人员想要的任何代码,例如导航到另一个页面。

我可能做错了,但目前,我的用户控件的 Tapped 事件处理程序启动了故事板动画:

 Storyboard f = new Storyboard();
        f = this.Pressed_Anim;        
        f.Begin();

然后控件实例的 Tapped 处理程序(即在页面后面的代码上)也运行。

如果实例的处理程序导航到新页面,则永远不会看到来自控件模板代码的动画,因为页面导航发生在 UI 更新之前。我希望动画在导航之前可见,就像标准按钮一样。

我这样做对吗?

注意:by control 不是继承Button,它是从零开始作为一个学习练习的。

我怀疑情节提要代码会有所帮助,但无论如何:

 <Storyboard x:Name="Pressed_Anim">
                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="grid">
                    <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                            <x:Int32>1</x:Int32>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.4">
                            <DiscreteObjectKeyFrame.Value>
                                <x:Int32>0</x:Int32>
                            </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
            </Storyboard>

【问题讨论】:

    标签: xaml windows-runtime win-universal-app


    【解决方案1】:

    您可能需要在情节提要完成后运行导航。只需订阅完成的事件,如下所示

    Storyboard f = new Storyboard();
    f = this.Pressed_Anim;  
    f.Completed += (s, args) =>
                {
                    //Perform your navigation here
                };
    f.Begin();
    

    EDIT 创建了一个快速示例来展示在用户控件中创建事件。 MyUserControl.xaml 有一个按钮,一个简单的动画,将一个矩形向右移动 100 像素

    <UserControl
    x:Class="App23.MyUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App23"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">
    <UserControl.Resources>
        <Storyboard x:Name="Storyboard1">
            <DoubleAnimation Duration="0:0:2" To="100" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
        </Storyboard>
    </UserControl.Resources>
    
    <Grid>
        <Button x:Name="RunStory" Width="120" Height="35" Content="run" Click="RunStory_Click" />
        <Rectangle x:Name="rectangle" Width="100" Height="100" Fill="Red" RenderTransformOrigin="0.5,0.5" >
            <Rectangle.RenderTransform>
                <CompositeTransform/>
            </Rectangle.RenderTransform>
        </Rectangle>
    </Grid>
    

    MyUserControl.cs

     public sealed partial class MyUserControl : UserControl
    {
        //Event
        public event EventHandler AnimationFinished;
    
    
        //Invokes event 
        public void OnAnimationFinsihed(EventArgs e)
        {
            var handler = AnimationFinished;
            if (handler != null)
                AnimationFinished(this, e);
        }
    
        public MyUserControl()
        {
            this.InitializeComponent();
        }
    
        private void RunStory_Click(object sender, RoutedEventArgs e)
        {
            Storyboard1.Completed += (s, args) =>
                {
                    //Animation has completed so lets invoke the event
                    OnAnimationFinsihed(new EventArgs());
                };
            Storyboard1.Begin();
        }
    }
    

    MainPage.xaml 只有一个 Grid 和 MyUserControl

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <local:MyUserControl x:Name="myUserControl" />
    </Grid>
    

    最后是出现导航的 MainPage.cs

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
    
        }
    
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            //Subscribes to AnimationFinished event of usercontrol
            myUserControl.AnimationFinished += (s, args) =>
                {
                    this.Frame.Navigate(typeof(Page2));
                };
        }
    
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            //unsubscribe from event when navigating away
            myUserControl.AnimationFinished -= (s, args) => { };
        }
    }
    

    【讨论】:

    • 问题是这两个事件是分开的——用户控件自己的代码在后面做动画,但导航是由按钮的单个实例触发的(即代码可以做任何开发人员想要的,而且我无法控制它在第一个处理程序完成后立即执行)。它们是由同一个按钮单击触发的两个独立类中的两个独立事件。
    • 想我明白你的意思了。使用自定义控件,我会在情节提要完成后引发自定义事件并在相关类中订阅该事件,然后执行导航。不确定用户控件我会尝试看看
    • 我确信这会起作用,但它并不能满足我的需求。我需要按钮像普通按钮一样工作(即我不想有额外的特殊代码来使它们正常工作)。在导航之前,我可以通过在按钮实例的事件处理程序中放置一个 Task.Delay 来获得我想要的效果,但这很丑,这意味着我必须将我的按钮与其他按钮区别对待。
    • 您将需要一个事件来说明相关课程如何知道您的故事板已完成。 Task.Delay 你说的更糟。无论如何我都会发布我的编辑
    • 内置控件(以及许多第 3 方控件)不需要事件,因此必须有方法。 Task.Delay 比事件要好,因为它至少需要一行代码,并且单击按钮时对性能的实际影响只有几分之一秒。
    【解决方案2】:

    下面的行为完全符合我的要求,但由于它使用 Task.Delay 可能不会扩展到其他用途(我只想让导航延迟几分之一秒,以便可以看到点击动画,制作按钮感觉触觉)。

    我在用户控件中添加了一个处理程序:

      base.Tapped += ButtonTapped;
    

    使用以下代码:

    private void ButtonTapped(object sender, TappedRoutedEventArgs e)
            {           
                Storyboard sBoard = this.Pressed_Anim;
                sBoard.Begin();   
            }

    然后在控件实例的 Tapped 处理程序中,在导航之前添加一个简短的 Task.Delay:

    private async void MyButton_Tapped(object sender, TappedRoutedEventArgs e)
            {
                await Task.Delay(100);
                Frame.Navigate(typeof(AboutPage));     
            }

    这种短暂的延迟会阻止导航与情节提要同时启动,因为页面上的控件自己的处理程序和实例的处理程序似乎是同时执行的。

    除非有更好的方法不需要用户控件自己的类之外的额外代码,否则这就足够了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-29
      • 1970-01-01
      • 2023-03-08
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多