【问题标题】:Execute command after animation动画后执行命令
【发布时间】:2015-05-04 13:01:59
【问题描述】:

我在屏幕上收集了一系列错误,一个错误一行。用户可以通过单击该行上的按钮来关闭任何错误消息。代码示例:

<UserControl>
    <ItemsControl ItemsSource="{Binding Errors}" >
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid x:Name="grid" Height="20">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding ErrorText}"/>
                    <Button Grid.Column="1" Width="16" Height="16" Content="Close" Command="{Binding DataContext.RemoveErrorCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" CommandParameter="{Binding CurrentError}">
                        <Button.Triggers>
                            <EventTrigger RoutedEvent="ButtonBase.Click">
                                <BeginStoryboard>
                                    <Storyboard TargetProperty="Height" TargetName="grid">
                                        <DoubleAnimation To="0" Duration="0:0:0.35"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </Button.Triggers>
                    </Button>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

出了什么问题:如您所见,我添加了带有情节提要的触发器以使其清楚,我想顺利隐藏消息,并且只有在关闭它之后。因此,首先是情节提要,然后执行命令。如何实现?请尽量减少代码隐藏。

【问题讨论】:

  • 这个答案应该为您指明正确的方向:stackoverflow.com/a/14124760/1231132 您可以保留现有的 Button 触发器,并添加一个额外的交互触发器来调用您的命令。

标签: c# wpf xaml mvvm


【解决方案1】:

您可以像这样使用附加属性:

public static class StoryboardHelper
{
    public static readonly DependencyProperty CompletedCommandProperty = DependencyProperty.RegisterAttached("CompletedCommand", typeof(ICommand), typeof(StoryboardHelper), new PropertyMetadata(null, OnCompletedCommandChanged));
    public static readonly DependencyProperty CompletedCommandParameterProperty = DependencyProperty.RegisterAttached("CompletedCommandParameter", typeof(object), typeof(StoryboardHelper), new PropertyMetadata(null));

    public static void SetCompletedCommand(DependencyObject o, ICommand value)
    {
        o.SetValue(CompletedCommandProperty, value);
    }

    public static ICommand GetCompletedCommand(DependencyObject o)
    {
        return (ICommand)o.GetValue(CompletedCommandProperty);
    }

    public static void SetCompletedCommandParameter(DependencyObject o, object value)
    {
        o.SetValue(CompletedCommandParameterProperty, value);
    }

    public static object GetCompletedCommandParameter(DependencyObject o)
    {
        return o.GetValue(CompletedCommandParameterProperty);
    }

    private static void OnCompletedCommandChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var sb = sender as Storyboard;

        if(sb != null)
        {
            sb.Completed += (a, b) =>
            {
                var command = GetCompletedCommand(sb);

                if (command != null)
                {
                    if (command.CanExecute(GetCompletedCommandParameter(sb)))
                    {
                        command.Execute(GetCompletedCommandParameter(sb));
                    }
                }
            };
        }
    }
}

并像这样使用它:

<Storyboard TargetProperty="Opacity" local:StoryboardHelper.CompletedCommand="{Binding Path=StoryCompletedCommand}">
    <DoubleAnimation From="0" To="1" Duration="0:0:5"/>
</Storyboard>

所以Command会在动画结束后触发。

【讨论】:

  • 如果它有效,那就太好了!试过这个,它抛出了一个异常“触发器动作已经被密封”。使用 VS2015 + .NET 4.5
【解决方案2】:

在 DoubleAnimation 中使用 Completed 事件处理程序

<Storyboard TargetProperty="Height" TargetName="grid">
       <DoubleAnimation To="0" Duration="0:0:0.35" Completed="do_this"/>
</Storyboard>

您必须在后面的代码中设置事件,但这对于您需要做的事情非常简单。

编辑:这是您应该在代码隐藏中获得的事件处理程序以及您需要删除用户控件的代码行

private void do_this(object sender, EventArgs e)
{
    this.Grid.Children.Remove(UserControl);
}

您需要为用户控件和它所在的网格设置一个 x:Name。我刚刚对此进行了测试,它确实有效,我认为您无法在不触及代码隐藏的情况下找到任何方法。

【讨论】:

  • 为什么投反对票?我不明白这怎么行。
  • 不是我的。在这个事件处理程序中,我们不能做任何事情——即使 DataContext 是不可访问的,所以作为必需的命令。这也是代码隐藏的方式,如果可能的话我想避免它
  • 我编辑了我的答案,为您提供了完成该工作所需的一切。我不知道为什么你之前对那个命令有问题,但我可以对完成的事件做很多事情。
  • 不是我的 DV,但可能是因为它没有遵循 MVVM(因为它使用后面的代码)。有没有可能改用命令?
  • 在某些情况下你可以使用它,例如如果你想改变可见性。但要实际删除需要使用后面代码的控件。
猜你喜欢
  • 2012-04-14
  • 1970-01-01
  • 2022-10-01
  • 2015-06-11
  • 1970-01-01
  • 2018-08-20
  • 1970-01-01
  • 1970-01-01
  • 2019-08-06
相关资源
最近更新 更多