Изменить порядок коллекции без добавления / удаления элементов? - PullRequest
1 голос
/ 02 сентября 2010

У меня есть TabControl, который можно изменить, перетаскивая вкладки. Текущий процесс удаляет элемент из списка и добавляет его в новое место. У меня были некоторые проблемы с производительностью при переключении вкладок из-за их сложности, поэтому я нашел альтернативу, которая хранит отображаемые вкладки и перезагружает их по запросу. Моя единственная проблема с ним заключается в том, что при перетаскивании вкладок он перерисовывает каждую вкладку и вызывает одинаковую задержку. Есть ли способ просто переместить элемент в коллекции вместо его добавления / удаления?

Или, если это не удалось, есть ли способ отменить добавление / удаление в событии OnItemsChanged во время операции перетаскивания? Процесс влияет на визуальное представление элемента управления, поэтому мне нужно фактически отменить событие добавления / удаления, если оно было вызвано операцией перетаскивания (пользователи также могут обычно добавлять / удалять вкладки).

Ответы [ 2 ]

2 голосов
/ 02 сентября 2010

Вы пытались связать TabControl.ItemsSource с представлением коллекции, а затем сортировать представление коллекции по индексу? Тогда ваша логика перемещения просто изменит индексы, и элементы вкладок будут упорядочены соответствующим образом.

0 голосов
/ 02 сентября 2010

Я закончил тем, что изменил свое событие OnItemsChanged, чтобы запускать код удаления с более низким приоритетом диспетчера, чем код добавления, поэтому он дает операции Add возможность отменить удаление и повторно использовать ContentPresenter объекта TabItem вместо рендеринга новогоone.

Исходный код, с которого я начал, был получен из здесь

Он в основном хранит TabItem ContentPresenters, поэтому при переключении вкладок он использует сохраненный ContentPresenter вместо перерисовки нового.,Вот изменения, которые я сделал в OnItemsChanged, чтобы Drag / Drop мог повторно использовать старый элемент вместо перерисовки нового

case NotifyCollectionChangedAction.Add:
case NotifyCollectionChangedAction.Remove:

    // Search for recently deleted items caused by a Drag/Drop operation
    if (e.NewItems != null && _deletedObject != null)
    {
        foreach (var item in e.NewItems)
        {
            if (_deletedObject == item)
            {
                // If the new item is the same as the recently deleted one (i.e. a drag/drop event)
                // then cancel the deletion and reuse the ContentPresenter so it doesn't have to be 
                // redrawn. We do need to link the presenter to the new item though (using the Tag)
                ContentPresenter cp = FindChildContentPresenter(_deletedObject);
                if (cp != null)
                {
                    int index = _itemsHolder.Children.IndexOf(cp);

                    (_itemsHolder.Children[index] as ContentPresenter).Tag =
                        (item is TabItem) ? item : (this.ItemContainerGenerator.ContainerFromItem(item));
                }
                _deletedObject = null;
            }
        }
    }

    if (e.OldItems != null)
    {
        foreach (var item in e.OldItems)
        {

            _deletedObject = item;

            // We want to run this at a slightly later priority in case this
            // is a drag/drop operation so that we can reuse the template
            // Render is good since a normal Removal of an item will run prior to adding a new one
            this.Dispatcher.BeginInvoke(DispatcherPriority.Render,
                new Action(delegate()
            {
                if (_deletedObject != null)
                {
                    ContentPresenter cp = FindChildContentPresenter(_deletedObject);
                    if (cp != null)
                    {
                        this._itemsHolder.Children.Remove(cp);
                    }
                }
            }
            ));
        }
    }
...