我有一个TabControl,可以通过拖放选项卡重新排列。当前进程从列表中删除项目并将其添加到新位置。由于选项卡的复杂程度,我在切换选项卡时遇到了一些性能问题,因此找到了一个替代方法,用于存储已呈现的选项卡并在请求时重新加载它们。我唯一的问题是,当拖放标签时,它会重新渲染每个标签并导致相同的延迟。有没有办法简单地移动集合中的项目而不是添加/删除它?
或者失败了,有没有办法在拖放操作期间取消OnItemsChanged
事件中的添加/删除?该过程会影响控件的可视化,因此我需要实际取消添加/删除事件,如果它是由拖放操作引起的(用户也可以正常添加/删除标签)。
答案 0 :(得分:2)
您是否尝试将TabControl.ItemsSource
绑定到集合视图,然后根据索引对集合视图进行排序?然后你的移动逻辑只会改变索引,标签项会相应地排序。
答案 1 :(得分:0)
我最终修改了我的OnItemsChanged
事件,以较低的调度程序优先级然后添加代码运行删除代码,因此它为Add操作提供了取消删除操作并重新使用TabItem的ContentPresenter而不是渲染的机会一个新的。
我开始使用的原始代码是从here
获得的它基本上存储TabItem ContentPresenters,因此在切换选项卡时,它使用存储的ContentPresenter而不是重新绘制新的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);
}
}
}
));
}
}