C# 列表视图多选

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/83945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 11:23:16  来源:igfitidea点击:

Listview Multiple Selection

提问by Evan

Is there any way to force a listview control to treat all clicks as though they were done through the Control key?

有没有办法强制列表视图控件将所有点击视为通过 Control 键完成的?

I need to replicate the functionality of using the control key (selecting an item sets and unsets its selection status) in order to allow the user to easily select multiple items at the same time.

我需要复制使用控制键的功能(选择一个项目集并取消其选择状态),以允许用户轻松地同时选择多个项目。

Thank you in advance.

先感谢您。

采纳答案by Ray Hayes

It's not the standard behaviour of the ListView control, even when MultiSelect is set to true.

这不是 ListView 控件的标准行为,即使 MultiSelect 设置为 true。

If you wanted to create your own custom control you would need to do the following:

如果您想创建自己的自定义控件,则需要执行以下操作:

  1. Derive a control from ListView
  2. add a handler to the "Selected" event.
  3. In the "OnSelected", maintain your own list of selected items.
  4. If the newly selected item is not in your list, add it. If it is, remove it.
  5. In code, select all of the items in your list.
  1. 从 ListView 派生控件
  2. 向“Selected”事件添加处理程序。
  3. 在“OnSelected”中,维护您自己的所选项目列表。
  4. 如果新选择的项目不在您的列表中,请添加它。如果是,请将其删除。
  5. 在代码中,选择列表中的所有项目。

Should be simple enough to implement and feel like multi-select without using the control key!

应该足够简单,可以在不使用控制键的情况下实现多选!

回答by user16009

The Ctrl+Click behavior is as implemented by the browser, and has little to do with the actual .NET Control. The result you're trying to achieve can be acquired with a lot of additional JavaScript - the easiest way would probably be to build a JavaScript control from default that works this way, rather than trying to hack up the listview. Would this be desirable? In that case I could look into it and get back to you with a solution.

Ctrl+Click 行为是由浏览器实现的,与实际的 .NET 控件几乎没有关系。您尝试实现的结果可以通过大量额外的 JavaScript 获得 - 最简单的方法可能是从默认情况下构建一个以这种方式工作的 JavaScript 控件,而不是尝试修改列表视图。这是可取的吗?在这种情况下,我可以调查一下,然后给你一个解决方案。

回答by BKimmel

Drill down through ListviewItemCollection and you can set the Selected property for individual items to true. This will, I believe, emulate the "multi-select" feature that you are trying to reproduce. (Also, as the above commenter mentioned, be sure to have the MultiSelect property of the lisetview set to true.)

深入查看 ListviewItemCollection,您可以将各个项目的 Selected 属性设置为 true。我相信,这将模拟您尝试重现的“多选”功能。(另外,正如上面的评论者提到的,确保将 lisetview 的 MultiSelect 属性设置为 true。)

回答by Chris Karcher

You might want to also consider using Checkboxeson the list view. It's an obvious way to communicate the multi-select concept to your average user who may not know about Ctrl+Click.

您可能还想考虑在列表视图上使用复选框。这是向可能不了解 Ctrl+Click 的普通用户传达多选概念的一种显而易见的方式。

From the MSDN page:

从 MSDN 页面:

The CheckBoxes property offers a way to select multiple items in the ListView control without using the CTRL key. Depending on your application, using check boxes to select items rather than the standard multiple selection method may be easier for the user. Even if the MultiSelect property of the ListView control is set to false, you can still display checkboxes and provide multiple selection capabilities to the user. This feature can be useful if you do not want multiple items to be selected yet still want to allow the user to choose multiple items from the list to perform an operation within your application.

CheckBoxes 属性提供了一种无需使用 CTRL 键即可在 ListView 控件中选择多个项目的方法。根据您的应用程序,使用复选框来选择项目而不是标准的多选方法对用户来说可能更容易。即使 ListView 控件的 MultiSelect 属性设置为 false,您仍然可以显示复选框并向用户提供多选功能。如果您不想选择多个项目,但仍希望允许用户从列表中选择多个项目以在您的应用程序中执行操作,则此功能非常有用。

回答by Matthew M.

Here is the complete solution that I used to solve this problem using WndProc. Basically, it does a hit test when the mouse is clicked.. then if MutliSelect is on, it will automatically toggle the item on/off [.Selected] and not worry about maintaining any other lists or messing with the ListView functionality.

这是我用来使用 WndProc 解决此问题的完整解决方案。基本上,它会在单击鼠标时进行命中测试。然后,如果 MutliSelect 处于打开状态,它将自动打开/关闭项目 [.Selected],而不必担心维护任何其他列表或弄乱 ListView 功能。

I haven't tested this in all scenarios, ... it worked for me. 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);
  }
}

回答by rdongart

Here is a complete solution that is a modification of the solution provided by Matthew M. above.

这是一个完整的解决方案,它是对上述 Matthew M. 提供的解决方案的修改。

It offers an improvement as well as a bit of added functionality.

它提供了改进以及一些附加功能。

Improvement:

改进:

  • left clicking the control gives focus to the control.
  • right mouse click behaviour is consistent (single selection)
  • 左键单击控件将焦点放在控件上。
  • 鼠标右键行为一致(单选)

Added functionality:

新增功能:

  • the control has a property (MultiSelectionLimit) that allows you to put a limit on how many items can be selected at once.
  • 该控件有一个属性 ( MultiSelectionLimit),允许您限制一次可以选择的项目数。

After my first posting I realised a minor problem with the code. Clearing multiple selections would lead to the ItemSelectionChangedevent being invoked multiple times.
I could find no way to avoid this with the current inheritance, so instead I adopted a solution where the bool property SelectionsBeingClearedwill be true while until all selected items have been deselected.

在我第一次发帖后,我意识到代码有一个小问题。清除多个选择会导致ItemSelectionChanged事件被多次调用。
我找不到通过当前继承来避免这种情况的方法,因此我采用了一个解决方案,其中 bool 属性SelectionsBeingCleared将为真,直到所有选定的项目都被取消选择为止。

This way a simple call to that property will make it possible to avoid updating effects until all of the multiple selections have been cleared.

这样,对该属性的简单调用就可以避免更新效果,直到所有多个选择都被清除。

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

回答by kamikazi

Just in case anyone else has searched for and found this article, the accepted solution is no longer valid. (in fact I am not sure it ever was). In order to do what you want (select multiple without a modifier key) simply set the list view selection type to be multiple, rather than extended. Multiple selects one item after another when clicked, and extended requires the modifier key to be pressed first.

以防万一其他人搜索并找到了这篇文章,接受的解决方案不再有效。(事实上​​,我不确定它曾经是否如此)。为了做你想做的事(不使用修饰键选择多个)只需将列表视图选择类型设置为多个,而不是扩展。单击时多选一个又一个,扩展需要先按下修饰键。