上下移动 ListViewItems

2024-03-20

我有一个 ListView (WinForms),我想通过单击按钮来上下移动项目。要移动的项目是已检查的项目。因此,如果选择了第 2、6 和 9 项,当我按下向上移动按钮时,它们将变为 1、5 和 8,并且这些位置上的项目将向下移动一步。

我觉得我把事情变得不必要地复杂了,如下所示。每个 ListViewItem 的第二个 SubItem 是一个数字,表示其在列表中的位置(从 1 开始)。

我将以下代码归咎于缺乏睡眠和咖啡,但如果您能找到一种更简单的方法来完成此任务,我将不胜感激。

private void sourceMoveUpButton_Click(object sender, EventArgs e)
    {
        List<Int32> affectedNumbers = new List<Int32>();
        bool foundNonChecked = false;

        List<KeyValuePair<int, ListViewItem>> newList = new List<KeyValuePair<int, ListViewItem>>();

        foreach (ListViewItem item in this.sourceListView.CheckedItems)
        {
            int newNum = int.Parse(item.SubItems[1].Text) - 1;

            if (newNum >= 1)
            {
                foreach (ListViewItem testItem in this.sourceListView.Items)
                {
                    if (int.Parse(testItem.SubItems[1].Text) == newNum && !testItem.Checked)
                    {
                        foundNonChecked = true;
                    }
                }

                if (foundNonChecked)
                {
                    item.SubItems[1].Text = newNum.ToString();
                    affectedNumbers.Add(newNum);
                }
            }
        }

        foreach (ListViewItem item in this.sourceListView.Items)
        {
            int num = int.Parse(item.SubItems[1].Text);

            if (affectedNumbers.Contains(num) && !item.Checked)
            {
                item.SubItems[1].Text = (num + affectedNumbers.Count).ToString();
            }

            newList.Add(new KeyValuePair<int, ListViewItem>(int.Parse(item.SubItems[1].Text), item));
            item.Remove();
        }

        newList.Sort((firstPair, secondPair) =>
            {
                return firstPair.Key.CompareTo(secondPair.Key);
            }
        );

        foreach (KeyValuePair<int, ListViewItem> pair in newList)
        {
            this.sourceListView.Items.Add(pair.Value);
        }
    }

EDIT我已将其简化为以下内容:

foreach (ListViewItem item in this.sourceListView.CheckedItems)
        {
            if (item.Index > 0)
            {
                int newIndex = item.Index - 1;
                this.sourceListView.Items.RemoveAt(item.Index);
                this.sourceListView.Items.Insert(newIndex, item);
            }
        }

        int index = 1;
        foreach (ListViewItem item in this.sourceListView.Items)
        {
            item.SubItems[1].Text = index.ToString();

            index++;
        }

但现在,如果我选择两个最上面的项目(或类似的项目),当我单击向上移动的按钮时,它们将交换位置。

第二次编辑
对于向上运动,一切正常,如下所示:

if (this.sourceListView.CheckedItems[0].Index != 0)
        {
            this.sourceListView.BeginUpdate();

            foreach (ListViewItem item in this.sourceListView.CheckedItems)
            {
                if (item.Index > 0)
                {
                    int newIndex = item.Index - 1;
                    this.sourceListView.Items.RemoveAt(item.Index);
                    this.sourceListView.Items.Insert(newIndex, item);
                }
            }

            this.updateListIndexText();

            this.sourceListView.EndUpdate();
        }

但对于向下运动,我似乎无法做到正确:

if (this.sourceListView.CheckedItems[this.sourceListView.CheckedItems.Count - 1].Index < this.sourceListView.Items.Count - 1)
        {
            this.sourceListView.BeginUpdate();

            foreach (ListViewItem item in this.sourceListView.CheckedItems)
            {
                if (item.Index < this.sourceListView.Items.Count - 1)
                {
                    int newIndex = item.Index + 1;
                    this.sourceListView.Items.RemoveAt(item.Index);
                    this.sourceListView.Items.Insert(newIndex, item);
                }
            }

            this.updateListIndexText();

            this.sourceListView.EndUpdate();
        }

它适用于向下移动单个项目,但当我选择多个项目时,它就不起作用。


尝试这样的事情:

foreach (ListViewItem lvi in sourceListView.SelectedItems)
{
    if (lvi.Index > 0)
    {
        int index = lvi.Index - 1;
        sourceListView.Items.RemoveAt(lvi.Index);
        sourceListView.Items.Insert(index, lvi);
    }
}

基本上只是删除该项目,然后将其插入到原来的位置之上。 ListView 会在插入后自动处理重新排列项目的顺序,因此不用担心。

Edit:两个最上面的项目交换的原因是顶部的项目永远不会移动(即我还没有实现wrap-around移动。然而,第二项可以自由移动,因此位于列表顶部。

要解决此问题,您可以执行以下两项操作之一:

  1. 实施环绕式重新洗牌(即顶部项目转到底部)
  2. 如果选择了顶部项目,则防止任何移动(检查 listview.Items[0].Selected)

至于文本的重做,就在原来的循环中进行即可。

环绕式实施:

foreach (ListViewItem lvi in sourceListView.SelectedItems)
{
    int index = lvi.Index > 0 ? lvi.Index - 1 : sourceListView.Items.Count - 1;
    sourceListView.Items.RemoveAt(lvi.Index);
    sourceListView.Items.Insert(index, lvi);

    if (index != sourceListView.Items.Count - 1) //not a wraparound:
    {
        //just swap the indices over.
        sourceListView.Items[index + 1].SubItems[1].Text = (index + 1).ToString();
        lvi.SubItems[1].Text = index.ToString();
    }
    else //item wrapped around, have to manually update all items.
    {
        foreach (ListViewItem lvi2 in sourceListView.Items)
            lvi2.SubItems[1].Text = lvi2.Index.ToString();
    }
}

Edit 2:

静态助手实现,无环绕:

private enum MoveDirection { Up = -1, Down = 1 };

private static void MoveListViewItems(ListView sender, MoveDirection direction)
{
    int dir = (int)direction;
    int opp = dir * -1;

    bool valid = sender.SelectedItems.Count > 0 &&
                    ((direction == MoveDirection.Down && (sender.SelectedItems[sender.SelectedItems.Count - 1].Index < sender.Items.Count - 1))
                || (direction == MoveDirection.Up && (sender.SelectedItems[0].Index > 0)));

    if (valid)
    {
        foreach (ListViewItem item in sender.SelectedItems)
        {
            int index = item.Index + dir;
            sender.Items.RemoveAt(item.Index);
            sender.Items.Insert(index, item);

            sender.Items[index + opp].SubItems[1].Text = (index + opp).ToString();
            item.SubItems[1].Text = (index).ToString();
        }
    }
}

Example:

MoveListViewItems(sourceListView, MoveDirection.Up);
MoveListviewItems(sourceListview, MoveDirection.Down);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

上下移动 ListViewItems 的相关文章

随机推荐

  • 如何构建一个 GUI 以在 jupyter 笔记本中使用?

    这个想法是能够在笔记本中构建和使用 GUI 因此使用具有大量参数的长函数比仅在笔记本中键入字符更有效 显然不是具体细节 但如果有人可以指出一些可能有帮助的库 项目 链接或任何资源 我查遍了互联网 到目前为止什么也没有 PyData 中有一个
  • git clone 不签出活动分支

    我有一个远程裸存储库 有两个分支 master 和 testing 其中 HEAD 指 testing 克隆此存储库时 git 检查 master 如果 master 和 testing 位于同一修订版上 即 HEAD test maste
  • Eclipse 任务为空

    我正在使用 Eclipse Helios 并在我的 java 类中添加了一些任务 使用 TODO blah blah 在行计数附近 我有一个小图标 表明任务已被识别 但我在任务视图中看不到它们 我尝试了任务视图和任务列表视图 它们是空的 但
  • 如何在量角器中调用另一个函数中的函数

    第一个功能 describe Shortlisting page function it Click on candidate status Screened function element by css i flaticon lefta
  • 以编程方式将下拉列表添加到特定单元格

    我想知道如何使用 VBA 以编程方式将下拉列表添加到 Excel 工作表的特定单元格 例如 我希望能够向单元格 i j 添加下拉列表并定义列表的元素 以编程方式执行此操作 With Selection Validation Delete A
  • 使用 dapper 查询空间数据

    我找到了一些相关的问题 https stackoverflow com questions 18088169 dapper spatial geography type 但作者放弃了 继续使用存储过程来进行 映射 这实际上是一个延续问题he
  • 如何使用 Laravel Passport 生成短令牌?

    我使用 Laravel Passport 和密码授予模式 我发现它生成的访问令牌很长 如下所示 token type Bearer expires in 31536000 access token eyJ0eXAiOiJKV1QiLCJhb
  • 没有 元素的 selenium 文件上传

    我正在尝试使用 selenium python 上传我的简历here https boards greenhouse io robinhood jobs 996796 app 在简历 简历附件部分下 当我检查 Attach 元素时 它显示为
  • java.lang.OutOfMemoryError:为 ChunkPool::allocate 请求 32756 字节。交换空间不足?

    我正在使用通过 WebLogic 10 3 部署在 HP 服务器上的 java 应用程序 版本信息 WebLogic Version 10 3 OS Version B 11 23 java version java version 1 6
  • 为什么这个工厂返回 $$state 对象而不是 response.data?

    所以我在服务器中有一个对象集合 我想在页面加载时填充 ng repeat 我创建了一个工厂 它从服务器上的资源中获取列表 如下所示 app factory objectArray http function http This is ret
  • 在 Elasticsearch 中搜索所有嵌套子级与给定查询匹配的对象

    给定一个具有以下映射的对象 a properties id type string b type nested properties key type string 我想检索该对象的所有实例 其中所有嵌套子对象都与给定查询匹配 例如 假设我
  • 如何使用 MATLAB 从 WEKA 检索类值

    我正在尝试使用 MATLAB 和 WEKA API 从 WEKA 检索类 一切看起来都很好 但类始终为 0 有什么想法吗 我的数据集有 241 个属性 将 WEKA 应用于该数据集我得到了正确的结果 创建第一个训练和测试对象 然后构建分类器
  • 是/否 - 有没有办法用纯 SVG 工具改进鼠标拖动?

    所以我花了一些时间尝试纯 无外部库 SVG 元素拖动 一般来说 一切正常 但是对于快速移动的鼠标来说存在一个令人讨厌的问题 当用户将可拖动的 SVG 元素靠近其边缘时 然后拖动 鼠标移动 这样的可拖动速度太快 鼠标 失去 可拖动 这里更详细
  • 带有 Picturebox 的 MouseWheel 事件?

    我想将鼠标悬停在图片框 或所有图片和主窗体 上并使用鼠标滚轮滚动 然而我没有运气 我编写了 pictureBox1 MouseWheel 并检查了增量 我在它 0 时设置了一个断点 到目前为止 无论我做什么 我都无法发生任何事情 我也尝试过
  • 在 UI-Grid 标题中实现多列分组有更好的方法吗?

    我尝试使用以下方法在 UI Grid 的列标题级别实现多列分组 我遵循的步骤 包括 UI 网格的以下标题单元格模板以及另一个 UI 网格行 div class ui grid header custom ui grid header div
  • 在动态创建的 Web 应用服务中添加自定义域

    我使用 REST API 创建了 azure Web 应用程序 是否有任何选项可以使用rest api 自定义域映射 通过下面的链接 我创建了新的网络应用服务 https learn microsoft com en us rest api
  • Ionic 3 启用单页滑回功能

    我已在根组件和模块配置中全局禁用 向后滑动
  • 替换三元运算中已弃用的“define(@array)”

    我有以下需要更正的代码 如defined array 在最新的 Perl 中已弃用 my inputs defined padSrc gt inouts padSrc gt inouts defined padSrc gt inputs p
  • 从“void*”到“unsigned char*”的转换无效

    我有以下代码 void buffer operator new 100 unsigned char etherhead buffer 尝试编译时 我收到该行的以下错误 error invalid conversion from void t
  • 上下移动 ListViewItems

    我有一个 ListView WinForms 我想通过单击按钮来上下移动项目 要移动的项目是已检查的项目 因此 如果选择了第 2 6 和 9 项 当我按下向上移动按钮时 它们将变为 1 5 和 8 并且这些位置上的项目将向下移动一步 我觉得