我需要的功能是在多选模式下复选框和列表框之间的交叉。
对于列表框项目A和B
A然后B导致从A移到B的单个选择。
A然后按住Control键并单击B会同时选择A和B。
((我想要的是):
我以为这很容易,但我不知道。也许我遗漏了一些明显的东西,或者我在想错误的方式,没有人真正想要列表框打开或关闭项目。
如果将SelectionMode设置为MultiSimple,则可以通过单击控制键进行多选并打开和关闭切换。
要使移动选择生效,您可以处理SelectedIndexChanged事件,并在未按下控件的情况下添加一些逻辑以取消选择其他项。如果以后有更多时间,我可以尝试为其创建一些基本代码,但这应该从某个地方开始。
如果将ListBox.SelectionMode设置为MultiExtended并在选择时按住控件,则已经具有想要的行为。
[如果我正确理解了您的问题,则需要ListBox
和SelectionMode.One
,该CTLR
可以使用SelectionMode.MultiSimple
和SelectionMode.MultiExtented
修饰符来切换选择。在我的答案下方,只需将ToggleSingleSelection
设置为true。另外,它还提供了单击事件,在单击已选择的项目时也会触发这些事件。
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Common
{
public class ListBoxEx : ListBox
{
public event ItemClickedEventHandler ItemClick;
public event ItemClickedEventHandler ItemDoubleClick;
/// <summary>
/// Toggle selections when list has SelectionMode.One
/// </summary>
public bool ToggleSingleSelection { get; set; }
int _PreSelectedIndex = -1;
int _PrevClickedItem = -1;
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
}
protected override void WndProc(ref Message m)
{
const int WM_LBUTTONDOWN = 0x201;
switch (m.Msg)
{
case WM_LBUTTONDOWN:
// NOTE: Unfortunately SelectedIndex is already setted before OnMouseDown,
// so we must intercept mouse click even before to compare
_PreSelectedIndex = SelectedIndex;
break;
}
base.WndProc(ref m);
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
// Reset clicked event, also for double click
_PrevClickedItem = -1;
int selectedIndex = SelectedIndex;
if (selectedIndex != -1)
{
Rectangle selectedItemRectangle = GetItemRectangle(selectedIndex);
if (selectedItemRectangle.Contains(e.Location))
{
_PrevClickedItem = selectedIndex;
// Check when to toggle selection
if (SelectionMode == SelectionMode.One && ToggleSingleSelection && ModifierKeys.HasFlag(Keys.Control)
&& _PreSelectedIndex != -1 && selectedIndex == _PreSelectedIndex)
{
SelectedIndex = -1;
}
if (_PrevClickedItem != -1)
OnItemClick(new ItemClickedEventArgs() { ItemIndex = _PrevClickedItem });
}
}
}
protected override void OnMouseDoubleClick(MouseEventArgs e)
{
base.OnMouseDoubleClick(e);
if (_PrevClickedItem != -1)
OnItemDoubleClick(new ItemClickedEventArgs() { ItemIndex = _PrevClickedItem });
}
protected virtual void OnItemDoubleClick(ItemClickedEventArgs args)
{
ItemDoubleClick?.Invoke(this, args);
}
protected virtual void OnItemClick(ItemClickedEventArgs args)
{
ItemClick?.Invoke(this, args);
}
}
public class ItemClickedEventArgs : EventArgs
{
public int ItemIndex { get; set; }
}
public delegate void ItemClickedEventHandler(Control sender, ItemClickedEventArgs args);
}