重新排列集合而不添加/删除项目?

发布于 2024-09-16 20:54:49 字数 324 浏览 9 评论 0原文

我有一个 TabControl,可以通过拖放选项卡来重新排列。当前进程从列表中删除一个项目并将其添加到新位置。由于选项卡非常复杂,我在切换选项卡时遇到了一些性能问题,因此找到了一种替代方案,可以存储渲染的选项卡并在请求时重新加载它们。我唯一的问题是,当拖/放选项卡时,它会重新渲染每个选项卡并导致相同的延迟。有没有一种方法可以简单地移动集合中的项目而不是添加/删除它?

或者如果失败,有没有办法在拖/放操作期间取消 OnItemsChanged 事件中的添加/删除?该过程会影响控件的视觉效果,因此如果添加/删除事件是由拖放操作引起的,我需要实际取消该事件(用户也可以正常添加/删除选项卡)。

I have a TabControl that can be rearranged by dragging/dropping the tabs. The current process removes an item from the list and adds it to a new location. I had some performance issues switching tabs because of how complex the tabs are, so found an alternative which stores the rendered tabs and reloads them when requested. My only problem with it is that when dragging/dropping tabs, it re-renders each tab and causes the same delay. Is there a way to simply Move the item in the collection instead of Adding/Removing it?

Or failing that, is there a way to cancel the addition/removal in the OnItemsChanged event during a drag/drop operation? The process affects the visual of the control, so I need to actually cancel the add/remove event if it was caused by a drag/drop operation (users can also add/remove tabs normally).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

×纯※雪 2024-09-23 20:54:50

您是否尝试过将 TabControl.ItemsSource 绑定到集合视图,然后根据索引对集合视图进行排序?然后您的移动逻辑将简单地更改索引,并且选项卡项目将相应地排序。

Have you tried binding the TabControl.ItemsSource to a collection view, and then sorting the collection view according to an index? Then your move logic would simply change the indexes and the tab items would order accordingly.

儭儭莪哋寶赑 2024-09-23 20:54:50

我最终修改了 OnItemsChanged 事件,以比添加代码更低的调度程序优先级运行删除代码,因此它使添加操作有机会取消删除并重用 TabItem 的 ContentPresenter 而不是渲染一个新的。

我开始使用的原始代码是从 此处

它基本上存储 TabItem ContentPresenter,因此在切换选项卡时,它使用存储的 ContentPresenter,而不是重绘一个新的。以下是我对 OnItemsChanged 所做的修改,以便通过拖/放重用旧项目,而不是重新绘制新项目

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);
                    }
                }
            }
            ));
        }
    }

I ended up modifying my OnItemsChanged event to run the Remove code at a lower dispatcher priority then the Add code, so it gives the Add operation a chance to cancel the Remove one and reuse the TabItem's ContentPresenter instead of rendering a new one.

Original code I started with was obtained from here

It basically stores the TabItem ContentPresenters so when switching tabs it uses a stored ContentPresenter instead of redrawing a new one. Here's the modifications I made to OnItemsChanged to get the Drag/Drop to reuse an old item instead of redrawing a new one

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);
                    }
                }
            }
            ));
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文