Как синхронизировать выбранные элементы и отмеченные элементы в ListView? - PullRequest
0 голосов
/ 10 января 2019

У меня есть ListView со свойством CheckBoxes, установленным на true, и со следующим обработчиком событий:

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

Использование клавиатуры:

Я могу переместить выделение влево или вправо с помощью клавиш со стрелками и (не) проверить элемент с помощью клавиши пробела. Я могу выбрать несколько элементов, используя клавиши Shift + стрелка.

Проблема: при нажатии клавиши пробела для снятия флажка с одного из отмеченных элементов выбор автоматически устанавливается на один элемент, который в данный момент находится в фокусе.

Использование мыши:

Элементы выбора и отмеченные элементы, кажется, синхронизированы, пока я не проверю два элемента, а затем не нажму левой кнопкой мыши на одном из их двух флажков, в тот момент, когда выбор будет отменен, а все отмеченные элементы станут непроверенными.

Пример снимков экрана:

Исходное состояние:

Initial state

, затем после щелчка левой кнопкой мыши на первом флажке и затем левой кнопкой мыши на втором флажке:

State 2

затем после щелчка левой кнопкой мыши на любом из двух флажков, снова начальное состояние:

Initial state again

Ожидаемое поведение : один из двух флажков (тот, который не был нажат на последнем шаге) должен оставаться отмеченным и выбранным.

Примечание: Я хочу иметь возможность использовать и другие виды ListView, свойство LabelEdit, перетаскивание, значки, мультиселектор, группы.

Я думал о возможности узнать координаты прямоугольника флажка и использовать событие MouseDown, или даже нарисовать мои собственные флажки, но, возможно, есть более простой или лучший способ.

Обновление 1 : В проводнике файлов в проводнике Windows 10 я могу включить функцию, которая делает это возможным:

Windows 10 File Explorer screenshot 1

Здесь первая папка (скрытая папка) не отмечена и не выбрана, а второй и третий элементы выбираются либо с помощью флажка, либо с помощью нажатия Ctrl +, либо с помощью обоих.

Еще один скриншот:

Windows 10 File Explorer screenshot 2

Я считаю разделение флажков и выбор ненужным, я думаю, что для пользователя более интуитивно понятно, если они объединены.

Я пытаюсь использовать выбор, а также флажки для выбора групп / папок для отображения в моем приложении.

Обновление 2: О коде, размещенном в этот связанный вопрос :

В этом коде есть несколько ошибок, одна из которых следующая:

Шаги для воспроизведения:

  1. Измените код конструктора, добавив всего 5 элементов в ListView.
  2. При запуске программы фокусируется первый элемент (не выбран и не отмечен).
  3. Нажатие клавиши со стрелкой вправо перемещает фокус на второй элемент.
  4. Когда я держу нажатой клавишу Shift и нажимаю правую клавишу со стрелкой, поведение оказывается неправильным: второй и третий элементы выбираются и проверяются, а после повторного нажатия стрелки вправо при нажатой клавише Shift только item3 и item4 получить выбор - точнее item2 и item3 проверяются, а item3 и item4 выбираются. Отпускание клавиши Shift и нажатие в пустом месте делает только отмеченный item3, и ни один не выбран.

В ответе Алексы Ристик есть несколько ошибок:

  1. двойной щелчок на ярлыке проверяет / снимает отметку, и состояние выбора противоположное;
  2. При выборе резиновой ленты флажки не установлены;
  3. после выбора элемента, нажав на ярлык и отметив, что он отменен.

Обновление 3 :

В ответе Алексы Ристик все еще есть ошибки, теперь я их вижу:

Я запускаю программу, затем я либо:

  1. непосредственно нажмите на ярлык или флажок;
  2. переместить фокус с помощью клавиш со стрелками;
  3. нажмите пробел или попробуйте выбор Shift;

и я всегда получаю System.StackOverflowException на одной строке i.Selected = false; (около строки 85).

Когда пользователь щелкает все и отменяет выделение, я хотел бы выделить выделенные и отмеченные элементы жирным шрифтом, а когда пользователь щелкает все, выделенные элементы и отмеченные элементы очищаются.

Когда пользователь нажимает на ярлык, мне бы хотелось, чтобы он работал так же, как когда он нажимал на флажок рядом с ярлыком.

Резиновая лента теперь работает очень хорошо.

1 Ответ

0 голосов
/ 17 января 2019

Так как этот вопрос был продвинут в комментариях, я решил удалить все и опубликовать готовый код.

  • Создать пустую форму
  • Добавить компонент ListView к нему с именем listView1
  • Вставьте этот код в вас .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;
        }
    }
}

Я думаю, у меня есть поведение, которое вы хотите. Если не спросите меня там, и я буду редактировать. В большинстве случаев это перемещение / изменение логических значений, но это нормально, если вы к этому не привыкли.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...