Анимация удаленного элемента в списке
У меня есть несколько списков в моем приложении, связанных с ObservableCollections, и я хотел бы анимировать элемент, если он удаляется.
Я уже нашел вопрос об анимации добавленных элементов с помощью события FrameworkElement.Loaded, но, конечно, это не работает так же, как с событием Unloaded.
Есть ли способ сделать это таким образом, который может быть использован в табличке данных?
РЕДАКТИРОВАТЬ: я подключился к событию CollectionChanged в моем ItemsSource и попытался применить анимацию вручную. В настоящее время это выглядит так:
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);
Проблема в том, что это не работает вообще. Элемент все еще просто исчезает. Элемент все еще там, когда метод вызывается, поэтому разве он не должен воспроизводить анимацию до того, как он исчезнет? Или я делаю это совершенно неправильно?
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);
}
}
Возможно, это не лучшее решение, но оно выполняет свою работу (по крайней мере, если я использую его только как стек).
Я решил это, добавив свойство IsRemoved к связанным элементам. Затем привязывается триггер события в шаблоне контейнера ListViewItem, который воспроизводит анимацию удаления, когда значение bool изменяется на true. Параллельно задача запускается с 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)));
});
}
У меня нет доступа к окну кода в данный момент, так что это немного не так, но вы могли бы расширить FrameworkElement с помощью события Unloading, а затем инициировать его из CollectionChanged в ObservableCollection. Это означает использование пользовательского ObservableColleciton и пользовательского класса FrameworkElement, но он может предложить вам то, что вам нужно?
Вы можете использовать Present.Commands Fluent API для изменения визуальных состояний во время выполнения команды. Я разместил пример анимации добавления и удаления элементов в списке с помощью его здесь http://adammills.wordpress.com/2011/01/11/mvvm-animation-of-listbox-present-commands/