【问题标题】:How to sync selected items and checked items in a ListView?如何同步 ListView 中的选定项目和选中项目?
【发布时间】:2019-01-10 12:54:16
【问题描述】:

我有一个 ListView,其属性 CheckBoxes 设置为 true 并具有以下事件处理程序:

private void listView1_ItemCheck(object sender, ItemCheckEventArgs e)
{
    listView1.Items[e.Index].Selected = e.NewValue == CheckState.Checked ? true : false;
}

使用键盘:

我可以使用箭头键向左或向右移动选择,并使用空格键(取消)选中一个项目。我可以使用 Shift + 箭头键选择多个项目。

问题:当按下空格键取消选中其中一个选中的项目时,选择会自动设置为单个项目,即当前聚焦的项目。

使用鼠标:

选择和检查元素似乎是同步的,直到我检查两个项目,然后左键单击其两个复选框中的一个复选框,时刻清除并检查的项目都不会被选中。

截图示例:

初始状态:

然后左键单击第一个复选框,然后左键单击第二个复选框:

然后左键单击两个复选框中的任何一个后,再次进入初始状态:

预期行为:两个复选框之一(上一步中未单击的那个)应保持选中状态。

注意:我也希望能够使用 ListView 的其他视图、LabelEdit 属性、拖放、图标、多选、组。

我想到了知道复选框矩形坐标的可能性,并使用 MouseDown 事件,甚至绘制我自己的复选框,但也许有更简单或更好的方法。

更新 1: 在 Windows 10 文件资源管理器的文件资源管理器中,我可以启用一个功能,使之成为可能:

这里第一个文件夹(隐藏文件夹)是不勾选不选中的,第二个和第三个项目要么是通过checkbox要么是通过Ctrl+click,要么是两者都选择。

另一个截图:

我发现复选框和选择的分离没有用,我认为如果将它们组合起来对用户来说更直观。

我正在尝试使用选择以及复选框来选择要在我的应用程序中显示的组/文件夹。

更新2:关于this related question中发布的代码:

该代码中存在一些错误,其中一个如下:

重现步骤:

  1. 修改设计器代码,在 ListView 中总共添加 5 项。
  2. 在程序开始时,第一个项目被聚焦(既未选择也未选中)。
  3. 按右箭头键可将焦点移至第二项。
  4. 当我按住 Shift 并按右箭头键时,行为错误:选择并检查了第二项和第三项,并且在按住 Shift 的同时再次按右箭头后,只有 item3item4被选中 - 更准确地说,item2item3 被选中,item3item4 被选中。松开 Shift 键并单击空白区域只会选中 item3,而不会选中任何一个。

Aleksa Ristic 的回答有一些错误:

  1. 双击标签勾选/取消勾选,选择状态相反;
  2. 橡皮筋选择不选中复选框;
  3. 一旦通过单击标签选择了一个项目,选中它就会取消选择。

更新 3

Aleksa Ristic 的回答还是有一些 bug,我现在看到了:

我启动程序然后我:

  1. 直接点击标签或复选框;
  2. 使用箭头键移动焦点;
  3. 按 Space 或尝试 Shift 选择;

我总是在同一行i.Selected = false;(靠近第 85 行)得到System.StackOverflowException

当用户点击所有内容并取消选择时,我想让当前选择和选中的项目变为粗体,当用户点击所有内容时,选择和选中的项目被清除。

当用户点击一个标签时,我想要与点击该标签附近的复选框时相同的行为。

橡皮筋现在效果很好。

【问题讨论】:

  • 这是ListView 的功能之一 - 您可以选择多个项目并通过单击复选框集体选中/取消选中它们。你到底想达到什么目的?
  • 我更新了我的问题以回答您的问题。谢谢。

标签: c# winforms listview


【解决方案1】:

由于这个问题在 cmets 中得到了推进,我决定删除所有内容并发布完成的代码。

  • 创建空表单
  • 添加 ListView 组件,名称为listView1
  • 将此代码粘贴到您的.cs 文件中

代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Magacin
{
    public partial class TestForm : Form
    {
        bool HandleSelectionChange = true;
        bool HandleCheckChange = true;
        bool TempStopDeslect = false;

        bool dragging = false;
        bool multiJob = false;


        public TestForm()
        {
            InitializeComponent();


            listView1.CheckBoxes = true;
            this.listView1.ItemCheck += OnCheck;
            this.listView1.ItemSelectionChanged += new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(this.listView1_ItemSelectionChanged);
            this.listView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listView1_KeyDown);
            this.listView1.KeyUp += new System.Windows.Forms.KeyEventHandler(this.listView1_KeyUp);
            this.listView1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.listView1_MouseDown);
            this.listView1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.listView1_MouseUp);


            listView1.Items.Add("Item1");
            listView1.Items.Add("Item2");
            listView1.Items.Add("Item3");
        }

        private ListViewItem GetItemFromPoint(ListView listView, Point mousePosition)
        {
            Point localPoint = listView.PointToClient(mousePosition);
            return listView.GetItemAt(localPoint.X, localPoint.Y);
        }

        private void OnCheck(object sender, ItemCheckEventArgs e)
        {
            if (!HandleCheckChange)
                return;

            ListViewItem item = GetItemFromPoint(listView1, Cursor.Position);

            if (item == null)
                return;

            if (e.Index != item.Index)
            {
                TempStopDeslect = true;
                e.NewValue = e.CurrentValue;
                return;
            }

            HandleSelectionChange = (multiJob) ? false : true;
            if (e.NewValue == CheckState.Checked)
            {
                listView1.Items[e.Index].Selected = true;
            }
            else
            {
                listView1.Items[e.Index].Selected = false;
            }
            HandleSelectionChange = true;
        }
        private void listView1_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            if (!HandleSelectionChange)
                return;

            bool temp = e.IsSelected;

            if (!TempStopDeslect)
            {
                if (!multiJob && !dragging)
                {
                    foreach (ListViewItem i in listView1.Items)
                    {
                        i.Checked = false;
                        i.Selected = false;
                    }
                }
            }
            else
                TempStopDeslect = false;

            HandleCheckChange = false;
            e.Item.Selected = temp;
            e.Item.Checked = e.IsSelected;
            HandleCheckChange = true;
        }

        private void listView1_MouseDown(object sender, MouseEventArgs e)
        {
            ListViewItem item = GetItemFromPoint(listView1, Cursor.Position);
            if (item == null)
                dragging = true;
        }
        private void listView1_MouseUp(object sender, MouseEventArgs e)
        {
            dragging = false;
        }

        private void listView1_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.KeyCode == Keys.Control) // Change this to whatever you want
                multiJob = true;
        }
        private void listView1_KeyUp(object sender, KeyEventArgs e)
        {
            multiJob = false;
        }
    }
}

我想我得到了你想要的行为。如果不在那里问我,我会编辑。在大多数情况下,它会移动/更改布尔值,但如果您不习惯它也没关系。

【讨论】:

  • 感谢您的想法。我已对问题添加了更新。
  • 嗯,这些是你需要自己做的事情,因为可能会有更多这样的“错误”,因为我不知道你期望的行为,但是对于上面的 3 个,我会问你,在你回答之后我会更新代码。第一:当用户单击标签(不是复选框)时,您是否希望项目被选中/取消选中,或者您什么都不想做(既不选择也不取消选择该项目)第二:在橡皮筋上,您还想选中这些框。您要保留其他已检查的检查吗?第三:哦,我会改变的。
  • 还有一个问题。当用户点击所有内容并取消选择时,您是否要取消全部选中?
  • 我已经编辑了帖子,所以第三个问题已经解决,等待答案,所以我可以继续前两个
  • 感谢您的努力。我用您的答案信息更新了问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-19
  • 1970-01-01
  • 1970-01-01
  • 2018-12-13
  • 2015-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多