【问题标题】:How to invoke command on storyboard completed in XAML如何在 XAML 中完成的情节提要上调用命令
【发布时间】:2025-11-28 06:35:01
【问题描述】:

我有一个按钮,它应该关闭当前窗口,然后打开另一个窗口。但我想先淡出窗口,然后再关闭它。我创建了一个故事板:

<Storyboard x:Key="Storyboard1">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Window">
            <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>

我有按钮:

<Button Content="Log In" Height="50" Margin="5" VerticalAlignment="Top" Width="190" DockPanel.Dock="Right" 
        Style="{DynamicResource ButtonLoginStyle}" Template="{DynamicResource ButtonBaseControlTemplate1}" 
        Command="{Binding LogInCommand}">
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.LostMouseCapture">
                    <BeginStoryboard Storyboard="{StaticResource Storyboard1}"></BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>

有没有办法在 XAML 中做到这一点?还是我应该在后面的代码中做到这一点?我正在尝试遵循 MVVM 原则,所以我想将故事板引用作为参数发送给命令是不可能的。

我还有一个问题,你们是否使用 Blend for Visual Studio 在 XAML 中创建 UI?还是自己编写代码更好?

【问题讨论】:

    标签: c# wpf xaml mvvm


    【解决方案1】:

    如果您遵循 MVVM 模式,我建议您在代码隐藏中编写纯 UI 相关(故事板动画)事件,而不是引入视图模型和模型。

    Model.cs - 核心业务逻辑

    ViewModel.cs - 为用户视图和数据加载操作的业务逻辑

    View.Xaml - UI 设计和数据绑定

    View.Xaml.Cs - 加载数据上下文和纯 UI 相关事件(例如:故事板动画)

    参考这篇文章:Most people are doing MVVM all wrong. Are you?

    【讨论】:

      【解决方案2】:

      您可以在 xaml 中编写这种故事板。 您需要创建一个针对您的窗口的故事板,因此您应该提供您的窗口名称。 DoubleAnimation 需要处理从 1 到 0 的“不透明度”,持续时间随心所欲。故事板有一个“已完成”事件,您可以在其中关闭窗口等。

      <EventTrigger RoutedEvent="Button.Click" SourceName="BeginButton">
         <BeginStoryboard Name="MyBeginStoryboard">
                  <Storyboard >
                    <DoubleAnimation 
                      Storyboard.TargetName="myWindow" 
                      Storyboard.TargetProperty="Opacity" 
                      Duration="0:0:5" From="1" To="0" />
                  </Storyboard>
                </BeginStoryboard>
      </EventTrigger>
      

      对于您的另一个问题,使用 blend 非常适合预览复杂的样式,但只有在您擅长编写 xaml 之后才能使用它。以我自己的观点 - 编写自己的 xaml 更好,以便更好地练习

      【讨论】:

        【解决方案3】:

        我鼓励你这样做来解决它。

        创建具有两个依赖属性的行为:

        public class StoryboardReactionBehavior : DependencyObject, IBehavior
        {
        public DependencyObject AssociatedObject { get; private set; }
        
        public void Attach(DependencyObject associatedObject)
        {
            AssociatedObject = associatedObject;
            (AssociatedObject as UIElement).Tapped += StoryboardReactionBehavior_Tapped;
        }
        
        private void StoryboardReactionBehavior_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
        {
        
        }
        
        public void Detach()
        {
            (AssociatedObject as UIElement).Tapped -= StoryboardReactionBehavior_Tapped;
        }
        

        }

        还有两个属性

        public Storyboard Storyboard
            {
                get { return (Storyboard)GetValue(StoryboardProperty); }
                set { SetValue(StoryboardProperty, value); }
            }
        
            public static readonly DependencyProperty StoryboardProperty =
                DependencyProperty.Register("Storyboard", typeof(Storyboard), typeof(StoryboardReactionBehavior), new PropertyMetadata(null, StoryboardChanged));
        
            private static void StoryboardChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                var behavior = d as StoryboardReactionBehavior;
                if(behavior.Storyboard !=null)
                {
                    behavior.Storyboard.Completed += (s, be) =>
                    {
                        if (behavior.Command != null)
                        {
                            behavior.Command.Execute(null);
                        }
                    };
                }
            }
            public ICommand Command
            {
                get { return (ICommand)GetValue(CommandProperty); }
                set { SetValue(CommandProperty, value); }
            }
        
            public static readonly DependencyProperty CommandProperty =
                DependencyProperty.Register("Command", typeof(ICommand), typeof(StoryboardReactionBehavior), new PropertyMetadata(null));
        

        最后让我们在反应发生时调用:

        private void StoryboardReactionBehavior_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
            {
                if (Storyboard != null)
                {
                    Storyboard.Begin();
                }
                else if(Command != null)
                { 
                  Command.Execute(null);
                }
        
            }
        

        我认为这是最优雅的解决方案,并且可以随处连接。

        【讨论】:

        • 一些展示如何使用它的 XAML 代码会很棒!我真的不知道如何使用它。
        最近更新 更多