【问题标题】:Animating removed item in Listbox动画列表框中删除的项目
【发布时间】:2009-04-26 17:27:13
【问题描述】:

我的应用程序中有一些列表框绑定到 ObservableCollections,如果项目被删除,我想对其进行动画处理。

我已经发现了一个关于使用 FrameworkElement.Loaded 事件为添加的项目设置动画的问题,但当然这与 Unloaded 事件的工作方式不同。

有什么方法可以在数据模板中使用吗?

编辑:我已经连接到我的 ItemsSource 中的 CollectionChanged 事件并尝试手动应用动画。目前它看起来像这样:

  ListBoxItem item = stack.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
        item.LayoutTransform = new ScaleTransform(1, 1);

    DoubleAnimation scaleAnimation = new DoubleAnimation(); 
    scaleAnimation.From = 1; 
    scaleAnimation.To = 0; 
    scaleAnimation.Duration = new Duration(new TimeSpan(0, 0, 0, 0, 500));
    ScaleTransform transform = (ScaleTransform)item.LayoutTransform;
    transform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);

问题是,它根本不起作用。该项目仍然只是弹出。调用该方法时该项目仍然存在,所以它不应该在它消失之前播放动画吗?还是我做错了?

【问题讨论】:

    标签: c# .net wpf xaml expression-blend


    【解决方案1】:

    我通过向绑定项目添加 IsRemoved 属性解决了这个问题。然后绑定 ListViewItem 容器模板中的事件触发器,当此布尔值更改为 true 时播放删除动画。同时,Task 以与动画持续时间匹配的 Task.Delay(n) 启动,然后从集合中实际删除。请注意,此删除需要分派给拥有该列表的线程以避免跨线程异常。

    void Remove(MyItem item, IList<MyItem> list)
    {
        item.IsRemoved = true;
    
        Task.Factory.StartNew(() =>
            {
                Task.Delay(ANIMATION_LENGTH_MS);
                Dispatcher.Invoke(new Action(() => list.Remove(item)));
            });
    }
    

    【讨论】:

    • 不应该等待延迟任务完成吗?
    【解决方案2】:

    目前我无法访问代码窗口,所以这有点过时了,但是您能否使用 Unloading 事件扩展 FrameworkElement,然后从 ObservableCollection 中的 CollectionChanged 启动它。这意味着使用自定义 ObservableColleciton 和自定义 FrameworkElement 类,但它可以为您提供所需的东西?

    【讨论】:

    • 已经有Unload事件。但无论如何它对动画毫无用处,因为这是元素存在的最后手段,并且在此事件发生后没有任何动画。
    【解决方案3】:

    您可以使用 Present.Commands Fluent API 在命令执行期间更改视觉状态。 我在这里发布了一个使用它在列表框中添加和删除项目的动画示例 http://adammills.wordpress.com/2011/01/11/mvvm-animation-of-listbox-present-commands/

    【讨论】:

    • 这是针对用户触发此命令的情况的解决方案...在我的情况下,我有由 Obtics 实现的 INotifyCollectionChanged 并在服务器端进行了更改...我不知道如何在此处对项目删除进行动画处理。 ..
    【解决方案4】:

    事实证明,即使我在删除它们之前提出了一个事件,它们也会立即被删除。因此,当我将其用作可观察堆栈时,我通过将已删除的元素留在集合中并稍后将其删除来解决此问题。像这样:

    public class ObservableStack<T> : ObservableCollection<T> 
    {
        private T collapsed;
        public event EventHandler BeforePop;
    
        public T Peek() {
            if (collapsed != null) {
                Remove(collapsed);
                collapsed = default(T);
            }
            return this.FirstOrDefault();
        }
    
        public T Pop() {
            if (collapsed != null) { Remove(collapsed); }
            T result = (collapsed = this.FirstOrDefault());
            if (BeforePop != null && result != null) BeforePop(this, new EventArgs());
            return result;
        }
    
        public void Push(T item) {
            if (collapsed != null) {
                Remove(collapsed);
                collapsed = default(T);
            }
            Insert(0, item);
        }
    }
    

    可能不是最好的解决方案,但它可以完成工作(至少如果我只将它用作堆栈)。

    【讨论】:

    • 在我的情况下,我有 3dparty INotifyCollectionChanged 由 Obtics 实现,并且偶尔会被服务器端事件更改...我不知道如何在此处动画项目删除...可能我应该通过自定义 INotifyCollectionChanged 和只是延迟删除动画的上升自定义事件。但这仅适用于每个事件和每个动画的 1 个项目。 INotifyCollectionChanged 合约假设每个实例都会立即通过事件更改它们的集合,如果我有延迟 - 下一个事件将向我发送元素索引,假设我已经通过以前的索引维护了我的集合。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多