2008-09-17 3 views
5

Есть ли способ заставить элемент управления listview обрабатывать все клики, как если бы они были выполнены с помощью клавиши управления?Listview Multiple Selection

Мне нужно реплицировать функциональные возможности с помощью управляющего ключа (выбор элементов и его статус выбора), чтобы позволить пользователю легко выбирать несколько элементов одновременно.

Заранее спасибо.

ответ

4

Это не стандартное поведение элемента управления ListView, даже если для параметра MultiSelect установлено значение true.

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

  1. Наследуйте управления от ListView
  2. добавить обработчик в «Избранное» событие.
  3. В разделе «OnSelected» сохраните свой собственный список выбранных элементов.
  4. Если только что выбранный элемент отсутствует в вашем списке, добавьте его. Если это так, удалите его.
  5. В коде выберите все элементы в своем списке.

Должно быть достаточно простым, чтобы реализовать и почувствовать себя как мульти-выбор без использования ключа управления!

+0

Я сам работал над этими строками, но хотел проверить и посмотреть, было ли что-то проще, прежде чем я продолжил исправление. Спасибо за ваш ответ. – Evan 2008-09-17 15:01:23

-2

Поведение Ctrl + Click реализовано браузером и имеет мало общего с реальным .NET Control. Результат, который вы пытаетесь достичь, может быть приобретен с большим количеством дополнительного JavaScript - самым простым способом, вероятно, будет создание управляющего JavaScript по умолчанию, который работает таким образом, вместо того, чтобы пытаться взломать список. Было бы желательно? В этом случае я мог бы рассмотреть это и вернуться к вам с решением.

+0

Ничего общего с браузером, он использует C# и WinForms! – 2008-09-17 14:57:32

+0

В любом случае, Javascript не может использоваться в среде winforms. – Evan 2008-09-17 14:58:42

0

Прокрутите список ListViewItemCollection и вы можете установить свойство Selected для отдельных элементов в true. Это, я считаю, эмулирует функцию «multi-select», которую вы пытаетесь воспроизвести. (Кроме того, как упоминалось выше, убедитесь, что свойство MultiSelect для lisetview установлено в true.)

2

Возможно, вы также захотите рассмотреть возможность использования Checkboxes в виде списка. Это очевидный способ передать концепцию multi-select вашему среднему пользователю, который может не знать о Ctrl + Click.

На странице MSDN:

Чекбоксы свойство предлагает способ выбрать несколько элементов в элементе управления ListView без использования клавиши CTRL. В зависимости от вашего приложения для пользователя может быть проще использовать флажки для выбора элементов, а не стандартный метод множественного выбора. Даже если для свойства MultiSelect элемента управления ListView установлено значение false, вы все же можете отображать флажки и предоставлять пользователю несколько возможностей выбора. Эта функция может быть полезна, если вы не хотите, чтобы несколько элементов были выбраны, но все же хотите разрешить пользователю выбирать несколько элементов из списка для выполнения операции в вашем приложении.

2

Вот полное решение, которое я использовал для решения этой проблемы с помощью WndProc. По сути, он выполняет тест при нажатии мыши. Тогда, если MutliSelect включен, он автоматически переключит элемент вкл./Выкл. [.Selected] и не беспокоится о сохранении каких-либо других списков или беспорядочном использовании функций ListView.

Я не тестировал это во всех сценариях ... это сработало для меня. YMMV.

public class MultiSelectNoCTRLKeyListView : ListView { 
    public MultiSelectNoCTRLKeyListView() { 

    } 

    public const int WM_LBUTTONDOWN = 0x0201; 
    protected override void WndProc(ref Message m) { 
    switch (m.Msg) { 
     case WM_LBUTTONDOWN: 
     if (!this.MultiSelect) 
      break; 

     int x = (m.LParam.ToInt32() & 0xffff); 
     int y = (m.LParam.ToInt32() >> 16) & 0xffff; 

     var hitTest = this.HitTest(x, y); 
     if (hitTest != null && hitTest.Item != null) 
      hitTest.Item.Selected = !hitTest.Item.Selected; 

     return; 
    } 

    base.WndProc(ref m); 
    } 
} 
2

Вот полное решение, которое является модификацией решения, предоставленного Matthew M. выше.

Он предлагает усовершенствование, а также добавленную функциональность.

Улучшение: - щелчок левой кнопкой мыши по управлению дает фокус на управление. - правильное поведение мыши соответствует (одиночный выбор)

Добавлена ​​функциональность: - элемент управления имеет свойство (MultiSelectionLimit), что позволяет поставить ограничение на сколько пунктов можно выбрать сразу.

После моего первого сообщения я понял небольшую проблему с кодом. Очистка нескольких выборок приведет к выходу события ItemSelectionChanged несколько раз. Я не мог найти способ избежать этого с помощью текущего наследования, поэтому вместо этого я принял решение, в котором свойство bool SelectionsBeingCleared будет истинным, пока все выбранные элементы не будут отменены. Таким образом, простой вызов этого свойства позволит избежать обновления эффектов до тех пор, пока все множественные выборы не будут очищены.

public class ListViewMultiSelect : ListView 
{ 
    public const int WM_LBUTTONDOWN = 0x0201; 
    public const int WM_RBUTTONDOWN = 0x0204; 

    private bool _selectionsBeingCleared; 
    /// <summary> 
    /// Returns a boolean indicating if multiple items are being deselected. 
    /// </summary> 
    /// <remarks> This value can be used to avoid updating through events before all deselections have been carried out.</remarks> 
    public bool SelectionsBeingCleared 
    { 
     get 
     { 
      return this._selectionsBeingCleared; 
     } 
     private set 
     { 
      this._selectionsBeingCleared = value; 
     } 
    } 
    private int _multiSelectionLimit; 
    /// <summary> 
    /// The limit to how many items that can be selected simultaneously. Set value to zero for unlimited selections. 
    /// </summary> 
    public int MultiSelectionLimit 
    { 
     get 
     { 
      return this._multiSelectionLimit; 
     } 
     set 
     { 
      this._multiSelectionLimit = Math.Max(value, 0); 
     } 
    } 

    public ListViewMultiSelect() 
    { 
     this.ItemSelectionChanged += this.multiSelectionListView_ItemSelectionChanged; 
    } 

    public ListViewMultiSelect(int selectionsLimit) 
     : this() 
    { 
     this.MultiSelectionLimit = selectionsLimit; 
    } 

    private void multiSelectionListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) 
    { 
     if (e.IsSelected) 
     { 
      if (this.MultiSelectionLimit > 0 && this.SelectedItems.Count > this.MultiSelectionLimit) 
      { 
       this._selectionsBeingCleared = true; 

       List<ListViewItem> itemsToDeselect = this.SelectedItems.Cast<ListViewItem>().Except(new ListViewItem[] { e.Item }).ToList(); 

       foreach (ListViewItem item in itemsToDeselect.Skip(1)) { item.Selected = false; } 

       this._selectionsBeingCleared = false; 

       itemsToDeselect[0].Selected = false; 
      } 

     } 

    } 

    protected override void WndProc(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case WM_LBUTTONDOWN: 
       if (this.SelectedItems.Count == 0 || !this.MultiSelect) { break; } 

       if (this.MultiSelectionLimit > 0 && this.SelectedItems.Count > this.MultiSelectionLimit) { this.ClearSelections(); } 

       int x = (m.LParam.ToInt32() & 0xffff); 
       int y = (m.LParam.ToInt32() >> 16) & 0xffff; 

       ListViewHitTestInfo hitTest = this.HitTest(x, y); 

       if (hitTest != null && hitTest.Item != null) { hitTest.Item.Selected = !hitTest.Item.Selected; } 

       this.Focus(); 

       return; 
      case WM_RBUTTONDOWN: 
       if (this.SelectedItems.Count > 0) { this.ClearSelections(); } 
       break; 
     } 

     base.WndProc(ref m); 
    } 

    private void ClearSelections() 
    { 
     this._selectionsBeingCleared = true; 

     SelectedListViewItemCollection itemsToDeselect = this.SelectedItems; 

     foreach (ListViewItem item in itemsToDeselect.Cast<ListViewItem>().Skip(1)) { item.Selected = false; } 

     this._selectionsBeingCleared = false; 

     this.SelectedItems.Clear(); 
    } 
} 
0

На всякий случай кто-то ещё искал и нашел эту статью, принятое решение больше недействительно. (на самом деле я не уверен, что это когда-либо было). Чтобы сделать то, что вы хотите (выберите несколько без ключа модификатора), просто установите тип выбора вида списка как несколько, а не расширенный. При щелчке по множественности выбирает один элемент за другим, а расширенный требует нажатия первой кнопки модификатора.