如何在ListView中同步选定的项目和选中的项目? [英] How to sync selected items and checked items in a ListView?

查看:53
本文介绍了如何在ListView中同步选定的项目和选中的项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a ListView with the property CheckBoxes set to true and with the following event handler:

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

使用键盘:

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

I can move the selection left or right using the arrow keys, and (un)check an item by using the Space key. I can select multiple items using Shift + arrow keys.

问题:当按下Space键取消选中其中一项时,所选内容将自动设置为单个项,即当前关注的项.

The problem: when pressing the Space key to uncheck one of the checked items, the selection is automatically set to be a single item, the currently focused item.

使用鼠标:

选择和选中的元素似乎是同步的,直到我选中两个项目,然后在其两个复选框之一被单击时单击鼠标左键,此时选中被清除并且选中的项目全部变为未选中状态.

Selection and checked elements seem to be synchronized, until I check two items and then left-click on one of their two check boxes, moment when the selection is cleared and checked items all become unchecked.

示例屏幕截图:

初始状态:

然后在第一个复选框上单击鼠标左键,然后在第二个复选框上单击鼠标左键:

then after left-clicking on the first check box and then left clicking on the second check box:

然后在两个复选框中的任意一个上单击鼠标左键,再次恢复初始状态:

then after left-clicking on any of the two check boxes, the initial state again:

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

Expected behavior: one of the two check boxes (the one that was not clicked in the last step) should stay checked and selected.

注意:我希望也可以使用ListView的其他视图,LabelEdit属性,下拉,图标,多选,组.

Note: I wish to be able to use other Views of the ListView as well, LabelEdit property, drag & drop, icons, multiselect, groups.

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

I thought of the possibility of knowing the coordinates of the checkbox rectangle, and using the MouseDown event, or even drawing my own checkboxes but maybe there is an easier or better way.

更新1 : 在Windows 10 File Explorer的File Explorer中,我可以启用一个使之成为可能的功能:

Update 1: In File Explorer in Windows 10 File Explorer I can enable a function that makes this possible:

此处未选中且未选中第一个文件夹(隐藏的文件夹),并且通过复选框或Ctrl + click或两者都选择了第二和第三项.

Here the first folder (hidden folder) is unchecked and not selected, and the second and third items are selected either through the checkbox or through Ctrl+click, or through both.

另一个屏幕截图:

我发现复选框和选择项之间的分隔没有用,我认为如果将它们组合在一起,对用户来说更直观.

I find the separation of the check boxes and selection useless, I think it is more intuitive for the user if they are combined.

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

I am trying to use selection and also check boxes for selecting which groups/folders to show in my application.

更新2:关于此相关问题中发布的代码:

Update 2: About the code posted in this related question:

该代码中存在一些错误,如下所示:

There are some bugs inside that code, one is the following:

复制步骤:

  1. 修改设计器代码,以将总共5个项目添加到ListView.
  2. 程序启动时,第一项被聚焦(既未选中也未选中).
  3. 按下向右箭头键会将焦点移至第二项.
  4. 当我按住Shift并按向右箭头键时,行为是错误的:选择并检查了第二项和第三项,并且在按住Shift的同时再次按向右箭头后,只有item3item4被选中-更准确地检查item2item3,并选择item3item4.松开Shift键并单击空白区域将仅选中item3,而未选择任何内容.
  1. Modify the designer code to add 5 items in total to the ListView.
  2. At start of program the first item is focused (neither selected nor checked).
  3. Pressing the right arrow key moves the focus to the second item.
  4. When I keep Shift pressed and press the right Arrow key, the behavior is wrong: the second and third items are selected and checked, and after pressing again the right arrow while Shift is pressed, only item3 and item4 get selected - more exactly item2 and item3 are checked, and item3 and item4 are selected. Releasing the Shift key and clicking in empty space makes only the item3 checked, and none are selected.

Aleksa Ristic的答案存在一些错误:

The answer of Aleksa Ristic has some bugs:

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

更新3 :

Aleksa Ristic的答案仍然存在一些错误,我现在看到了这些错误:

The answer of Aleksa Ristic still has some bugs, I see these now:

我启动程序,然后我要么:

I start the program then I either:

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

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

and I always get System.StackOverflowException on the same line i.Selected = false; (near line 85).

当用户从所有内容中单击并取消选择时,我想使当前选中和选中的项目变为粗体,而当用户从所有内容中单击时,将清除选择和选中的项目.

When the user clicks out of everything and deselects, I would like to make the currently selected and checked items bold and when the user clicks out of everything, the selection and checked items are cleared.

当用户单击标签时,我希望具有与单击该标签附近的复选框时相同的行为.

When the user clicks on a label I would like the same behavior like when it clicks on the checkbox near that label.

橡皮筋现在真的很好用.

The rubberband works really well now.

推荐答案

由于此问题的注释日益完善,我决定删除所有内容并发布完成的代码.

Since this question got advanced in comments, i decided to delete everything and post finished code.

  • 创建空表格
  • 添加名称为listView1
  • 的ListView组件
  • 将此代码粘贴到您的.cs文件中
  • Create empty Form
  • Add ListView component to it with name listView1
  • Paste this code in you .cs file

代码:

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

我想我有想要的行为.如果不问我在那边,我会编辑.在大多数情况下,它会移动/更改布尔值,但是如果您不习惯它也可以.

I think i got behavior you want. If not ask me down there and i will edit. In most cases it is moving/changing boolean values but it is okay if you are not getting used to it.

这篇关于如何在ListView中同步选定的项目和选中的项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆