C# 我如何制作一个WinForms ListBox谁';s项开关打开和关闭

C# 我如何制作一个WinForms ListBox谁';s项开关打开和关闭,c#,winforms,listbox,C#,Winforms,Listbox,我想要的功能是复选框和多选模式下的列表框之间的交叉 对于列表框项目A和B A然后B产生从A到B的单个选择 A然后单击控制按钮B将导致A和B的多重选择 (我想要的是): A然后A会导致A开关切换 我以为这很容易,但我想不出来。可能我遗漏了一些明显的东西,或者可能我的想法不对,没有人真的想要一个列表框来打开/关闭项目。如果您将SelectionMode设置为MultiSimple,这会让您控制单击multi selection并打开和关闭切换 要使移动选择生效,您可以处理SelectedIn

我想要的功能是复选框和多选模式下的列表框之间的交叉

对于列表框项目A和B

  • A然后B产生从A到B的单个选择

  • A然后单击控制按钮B将导致A和B的多重选择

(我想要的是):

  • A然后A会导致A开关切换

我以为这很容易,但我想不出来。可能我遗漏了一些明显的东西,或者可能我的想法不对,没有人真的想要一个列表框来打开/关闭项目。

如果您将SelectionMode设置为MultiSimple,这会让您控制单击multi selection并打开和关闭切换


要使移动选择生效,您可以处理SelectedIndexChanged事件,并添加一些逻辑,以便在未按control键的情况下取消选择其他项目。如果我以后有更多的时间,我可以尝试为它创建一些基本代码,但这应该是开始的地方。

如果您将ListBox.SelectionMode设置为MultiExtend,并在进行选择时按住control键,您已经有了所需的行为。

如果我正确理解您的问题,您需要一个带有
SelectionMode的
ListBox
。一个可以使用
CTLR
修改器切换选择的
列表框,类似于
SelectionMode.MultiSimple
SelectionMode.multiextended
。在我的答案下面,只需将
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);
}
使用系统;
使用系统图;
使用System.Windows.Forms;
名称空间公用
{
公共类ListBoxEx:ListBox
{
公共事件项ClickedEventHandler项Click;
公共事件项ClickedEventHandler项双击;
/// 
///当列表具有SelectionMode.One时切换选择
/// 
public bool ToggleSingleSelection{get;set;}
int _预选索引=-1;
int_PrevClickedItem=-1;
受保护的覆盖无效OnSelectedIndexChanged(EventArgs e)
{
基础。根据所选指标变更(e);
}
受保护的覆盖无效WndProc(参考消息m)
{
常数int WM_LBUTTONDOWN=0x201;
开关(m.Msg)
{
案例WM_LBUTTONDOWN:
//注意:不幸的是,在OnMouseDown之前已设置SelectedIndex,
//所以我们必须拦截鼠标点击,甚至在比较之前
_预选索引=已选索引;
打破
}
基准WndProc(参考m);
}
鼠标单击时受保护的覆盖无效(鼠标目标e)
{
base.OnMouseClick(e);
//重置单击事件,也用于双击
_PrevClickedItem=-1;
int selectedIndex=selectedIndex;
如果(已选择索引!=-1)
{
矩形selectedItemRectangle=GetItemRectangle(selectedIndex);
if(selectedItemRectangle.Contains(如位置))
{
_PrevClickedItem=已选择的索引;
//检查何时切换选择
if(SelectionMode==SelectionMode.One&&ToggleSingleSelection&&ModifierKeys.HasFlag(Keys.Control)
&&\u预选索引!=-1&&selectedIndex==\u预选索引)
{
SelectedIndex=-1;
}
如果(_PrevClickedItem!=-1)
OnItemClick(新项目ClickedEventArgs(){ItemIndex=\u PrevClickedItem});
}
}
}
鼠标双击时受保护的覆盖无效(鼠标目标e)
{
base.onmouse双击(e);
如果(_PrevClickedItem!=-1)
OnItemDoubleClick(新项目ClickedEventArgs(){ItemIndex=\u PrevClickedItem});
}
受保护的虚拟磁盘OnItemDoubleClick(ItemClickedEventArgs参数)
{
ItemDoubleClick?.Invoke(此参数为args);
}
受保护的虚拟磁盘单击(ItemClickedEventArgs参数)
{
ItemClick?.Invoke(这个,args);
}
}
公共类项目ClickedEventArgs:EventArgs
{
公共int ItemIndex{get;set;}
}
公共委托无效项ClickedEventHandler(控制发送方,项ClickedEventTargets参数);
}

标题很清楚,但你的问题确实不清楚。您只是要求一个带有
SelectionMode.One
的列表框与
SelectionMode.MultiSimple
SelectionMode.multiextended
进行类似的切换吗?我会补充这个问题的答案,但请重新措辞。