6

有什么方法可以强制 listview 控件将所有点击视为通过 Control 键完成的?

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

先感谢您。

4

7 回答 7

4

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

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

  1. 从 ListView 派生控件
  2. 向“Selected”事件添加处理程序。
  3. 在“OnSelected”中,维护您自己的选定项目列表。
  4. 如果新选择的项目不在您的列表中,请添加它。如果是,请将其删除。
  5. 在代码中,选择列表中的所有项目。

应该足够简单,无需使用控制键即可实现并感觉像多选!

于 2008-09-17T14:57:02.213 回答
3

这是一个完整的解决方案,它是对上述 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();
    }
}
于 2013-05-03T02:04:10.130 回答
2

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

从 MSDN 页面:

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

于 2008-09-17T15:15:21.170 回答
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);
  }
}
于 2010-04-20T19:50:17.823 回答
0

向下钻取 ListviewItemCollection,您可以将单个项目的 Selected 属性设置为 true。我相信,这将模拟您尝试重现的“多选”功能。(另外,正如上述评论者所提到的,请确保将 lisetview 的 MultiSelect 属性设置为 true。)

于 2008-09-17T15:06:04.470 回答
0

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

于 2016-10-07T07:01:00.647 回答
-2

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

于 2008-09-17T14:54:55.697 回答