【问题标题】:How to stop Storyboard animation applied to ListBoxItem?如何停止应用于 ListBoxItem 的情节提要动画?
【发布时间】:2016-06-23 12:58:37
【问题描述】:

在我的聊天应用程序中,我有一个用户列表框,其中发送消息的任何人都在其中发送消息,如果他的聊天窗口未在用户侧打开,则他的名字开始在列表框中闪烁以通知用户传入消息。 如果用户选择该发送者,我将删除动画。但动画仅针对最后应用动画的元素停止。

以下是我用于将动画应用于 listboxItem 的代码,

   private void BlinkSenderUsername(int index, string userRole)
    {
        blinkAnimation = new DoubleAnimationUsingKeyFrames();
        blinkAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
        blinkAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(250))));
        ListBoxItem target = new ListBoxItem();

    target = OnlineUserList.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;
        OnlineUserList.ScrollIntoView(target);

        blinkStoryboard = new Storyboard
        {
            Duration = TimeSpan.FromMilliseconds(900),
            RepeatBehavior = RepeatBehavior.Forever,
        };

        Storyboard.SetTarget(blinkAnimation, target);
        Storyboard.SetTargetProperty(blinkAnimation, new PropertyPath(OpacityProperty));

        blinkStoryboard.Children.Add(blinkAnimation);
        blinkStoryboard.Begin(target, true);
    }

和列表框的选择更改事件(在选择时停止动画):

   private void OnlineUserListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
    ListBoxItem listBoxItem = OnlineUserList.ItemContainerGenerator.ContainerFromItem(OnlineUserList.SelectedItem) as ListBoxItem;
                if (listBoxItem != null && listBoxItem.HasAnimatedProperties)
                {
                    blinkStoryboard.Stop(listBoxItem);
                }

}

谁能建议,我做错了什么?

编辑(根据 Jai 的回答):-

    static void MyClassStaticConstructor()
    {
        BlinkAnimation = new DoubleAnimationUsingKeyFrames();
        BlinkAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
        BlinkAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(250))));

        BlinkStoryboard = new Storyboard
        {
            Duration = TimeSpan.FromMilliseconds(900),
            RepeatBehavior = RepeatBehavior.Forever,
        };

        BlinkStoryboard.Children.Add(BlinkAnimation);
    }

    private void BlinkSenderUsername(int index, string userRole)
    {
        // There is no need to instantiate a ListBoxItem
        //ListBoxItem target = new ListBoxItem();
          ListBoxItem target = OnlineUserList.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;

        if (target == null) return;
        MyClassStaticConstructor();
        Storyboard.SetTarget(BlinkAnimation, target);
        Storyboard.SetTargetProperty(BlinkAnimation, new PropertyPath(OpacityProperty));

        BlinkStoryboard.Begin(target, true);
    }

并在列表框的 selectionchanged 事件中:

    private void OnlineUserListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBoxItem listBoxItem = OnlineUserList.ItemContainerGenerator.ContainerFromItem(OnlineUserList.SelectedItem) as ListBoxItem;
            if (listBoxItem != null && listBoxItem.HasAnimatedProperties)
            {
                BlinkStoryboard.Stop(listBoxItem);
            }} 

【问题讨论】:

  • 什么是“但是除了首先应用动画的元素之外的所有其他列表框项的动画停止。”是什么意思?
  • 我可以在选择时停止所有其他发件人的动画,但第一次应用动画的 SenderName 除外(即假设用户从 UserA 收到消息,然后他的名字开始闪烁并再次用户收到来自 UserB 的消息(开始闪烁),如果我单击 UserB,则动画停止,但如果我单击 UserA,它会继续闪烁。)。现在清楚了吗?
  • 再次调试代码,发现动画只会在最后应用的元素上停止。
  • 您的blinkStoryboard 是一个全局字段,对吗?它保留了您设置的最后一个动画的引用,因为您每次设置它时都在“更新”它。
  • @Jai 是的,它是全局声明的字段,因为我想在列表框的选择更改事件中访问它以停止 listboxItem 的动画。

标签: c# wpf listbox


【解决方案1】:

问题在于,对于每个ListBoxItem,您正在创建一个Storyboard 和一个Animation 对象。情节提要和动画对象都保存到单个全局字段中。当您设置多个此类动画时,您的全局字段将具有仅最后添加的动画/故事板的引用。

将实现更改为:

private static readonly DoubleAnimationUsingKeyFrames BlinkAnimation;
private static readonly Storyboard BlinkStoryboard;

static MyClassStaticConstructor()
{
    BlinkAnimation = new DoubleAnimationUsingKeyFrames();
    BlinkAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
    BlinkAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(250))));

    BlinkStoryboard = new Storyboard
    {
        Duration = TimeSpan.FromMilliseconds(900),
        RepeatBehavior = RepeatBehavior.Forever,
    };

    BlinkStoryboard.Children.Add(blinkAnimation);
}

private void BlinkSenderUsername(int index, string userRole)
{
    // There is no need to instantiate a ListBoxItem
    //ListBoxItem target = new ListBoxItem();
    ListBoxItem target = OnlineUserList.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;

    if (target == null) return; // Just make sure we managed to get a ListBoxItem instance
    OnlineUserList.ScrollIntoView(target);

    Storyboard.SetTarget(BlinkAnimation, target);
    Storyboard.SetTargetProperty(BlinkAnimation, new PropertyPath(OpacityProperty));

    BlinkStoryboard.Begin(target, true);
}

动画和故事板对象是可重复使用的 - 因此如果多个控件需要相同的动画,它们可以使用相同的动画/故事板实例。你只需要实例化一次。在我的回答中,我已将它们设为静态,但您可以选择不将它们设为静态。

【讨论】:

  • 我在 Storyboard.SetTarget(BlinkAnimation, target); 上方遇到了所谓的 MyClassStaticConstructor() 空引用异常;但问题还是一样;动画仅针对最后一项停止
  • 非常感谢 Jai 的解决方案。它终于按我想要的方式工作了。你拯救了我的一天。非常感谢朋友。 :)
猜你喜欢
  • 1970-01-01
  • 2014-04-16
  • 2019-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-23
  • 2011-08-03
  • 2011-04-19
相关资源
最近更新 更多