C# WINFORM多选下拉框实现

C# WINFORM多选下拉框实现

效果如如下:

思路
1.基于原生控件ComboBox和CheckedListBox来实现,其中ComboBox负责显示多选结果和提供下拉按钮,然后CheckedListBox负责提供下拉多选操作
2.ComboBox设置为自绘,DropDownStyle为ComboBoxStyle.DropDown,下拉高度为1,属性代码设置代码参考如下:

ComboBox = new ComboBox();
ComboBox.Width = 150;
ComboBox.DrawMode = DrawMode.OwnerDrawFixed;
ComboBox.IntegralHeight = false;
ComboBox.DroppedDown = false;
ComboBox.DropDownHeight = 1;
ComboBox.Margin = new Padding(0);
ComboBox.Location = new Point(0, 0);
ComboBox.DropDownStyle = ComboBoxStyle.DropDown;
ComboBox.AutoCompleteSource = AutoCompleteSource.ListItems;

3.CheckedListBox属性CheckOnClick设置为true,同时初始化为不可见,参考代码如下:

CheckedListBox = new CheckedListBox();
CheckedListBox.CheckOnClick = true;
CheckedListBox.BorderStyle = BorderStyle.Fixed3D;
CheckedListBox.Visible = false;
CheckedListBox.Margin = new Padding(0);

4.然后就是处理控件的事件响应了,其中ComboBox需要处理事件MouseDown,MouseLeaveDropDown,代码如下:

ComboBox.MouseDown += (ss, se) =>
{
    ComboBox.DroppedDown = false;
};
ComboBox.MouseLeave += (ss, se) =>
{
    // 不在下拉区则隐藏下拉
    var curMousePos = this.PointToClient(Control.MousePosition);
    var downArea = CheckedListBox.Location;
    if (curMousePos.X < downArea.X || curMousePos.X > (downArea.X + CheckedListBox.Width)
    || curMousePos.Y < downArea.Y || curMousePos.Y > (downArea.Y + CheckedListBox.Height))
    {
        CheckedListBox.Hide();
    }
};
ComboBox.DropDown += (ss, se) =>
{
    // 显示下拉多选框
    CheckedListBox.Items.Clear();

    // 添加并设置选中项
    var lastChecked = ComboBox.Tag as List<string>;
    ComboBox.BeginUpdate();
    foreach (var v in this.Items)
    {
        var ck = false;
        if(lastChecked != null && lastChecked.IndexOf(v.ToString())>=0)
        {
            ck = true;
        }
        CheckedListBox.Items.Add(v, ck);
    }
    // 显示下拉框
    CheckedListBox.Width = ComboBox.Width;
    CheckedListBox.ItemHeight = ComboBox.ItemHeight;
    CheckedListBox.Size = new Size(ComboBox.DropDownWidth, this.Items.Count * 18);
    CheckedListBox.Location = new Point(ComboBox.Left, ComboBox.Height);
    this.Controls.Add(CheckedListBox);
    CheckedListBox.Visible = true;
    ComboBox.EndUpdate();
};

5.还要继续处理控件CheckedListBox的事件,包括MouseUpMouseLeave,代码如下:

CheckedListBox.MouseUp += (ss, se) =>
{
    // 更新ComboBox显示文本
    var lst = new List<string>();
    foreach (var v in CheckedListBox.CheckedItems)
    {
        lst.Add(v.ToString());
    }
    ComboBox.Text = string.Join(",", lst);
    ComboBox.Tag = lst;
};
CheckedListBox.MouseLeave += (ss, se) =>
{
    // 隐藏下拉多选框
    CheckedListBox.Hide();
};

完整代码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ControlEx
{
    #region 简单的多选下拉框
    public class MultiComboBox : UserControl
    {
        #region 属性
        public ComboBox ComboBox { get; set; }
        public CheckedListBox CheckedListBox { get; set; }
        public ComboBox.ObjectCollection Items
        {
            get
            {
                return ComboBox?.Items;
            }
        }
        #endregion

        /// <summary>
        /// 多选下拉框
        /// </summary>
        public MultiComboBox()
        {
            // 面板
            this.VerticalScroll.Enabled = true;
            this.AutoSize = true;

            // 多选列表
            CheckedListBox = new CheckedListBox();
            CheckedListBox.CheckOnClick = true;
            CheckedListBox.BorderStyle = BorderStyle.Fixed3D;
            CheckedListBox.Visible = false;
            CheckedListBox.Margin = new Padding(0);
            CheckedListBox.MouseUp += (ss, se) =>
            {
                // 更新ComboBox显示文本
                var lst = new List<string>();
                foreach (var v in CheckedListBox.CheckedItems)
                {
                    lst.Add(v.ToString());
                }
                ComboBox.Text = string.Join(",", lst);
                ComboBox.Tag = lst;
            };
            CheckedListBox.MouseLeave += (ss, se) =>
            {
                // 隐藏下拉多选框
                CheckedListBox.Hide();
            };

            // 下拉框
            ComboBox = new ComboBox();
            ComboBox.Width = 150;
            ComboBox.DrawMode = DrawMode.OwnerDrawFixed;
            ComboBox.IntegralHeight = false;
            ComboBox.DroppedDown = false;
            ComboBox.DropDownHeight = 1;
            ComboBox.Margin = new Padding(0);
            ComboBox.Location = new Point(0, 0);
            ComboBox.DropDownStyle = ComboBoxStyle.DropDown;
            ComboBox.AutoCompleteSource = AutoCompleteSource.ListItems;
            ComboBox.MouseDown += (ss, se) =>
            {
                ComboBox.DroppedDown = false;
            };
            ComboBox.MouseLeave += (ss, se) =>
            {
                // 不在下拉区则隐藏下拉
                var curMousePos = this.PointToClient(Control.MousePosition);
                var downArea = CheckedListBox.Location;
                if (curMousePos.X < downArea.X || curMousePos.X > (downArea.X + CheckedListBox.Width)
                || curMousePos.Y < downArea.Y || curMousePos.Y > (downArea.Y + CheckedListBox.Height))
                {
                    CheckedListBox.Hide();
                }
            };
            ComboBox.DropDown += (ss, se) =>
            {
                // 显示下拉多选框
                CheckedListBox.Items.Clear();

                // 添加并设置选中项
                var lastChecked = ComboBox.Tag as List<string>;
                ComboBox.BeginUpdate();
                foreach (var v in this.Items)
                {
                    var ck = false;
                    if(lastChecked != null && lastChecked.IndexOf(v.ToString())>=0)
                    {
                        ck = true;
                    }
                    CheckedListBox.Items.Add(v, ck);
                }
                // 显示下拉框
                CheckedListBox.Width = ComboBox.Width;
                CheckedListBox.ItemHeight = ComboBox.ItemHeight;
                CheckedListBox.Size = new Size(ComboBox.DropDownWidth, this.Items.Count * 18);
                CheckedListBox.Location = new Point(ComboBox.Left, ComboBox.Height);
                this.Controls.Add(CheckedListBox);
                CheckedListBox.Visible = true;
                ComboBox.EndUpdate();
            };

            // 添加控件
            this.Controls.Add(ComboBox);
        }
    }
    #endregion
}

测试代码

var panel = this.flowLayoutPanelMain;
var dropDown = new ControlEx.MultiComboBox();
dropDown.Items.AddRange(new string[] { "选项1", "选项2", "选项3", "选项4", "选项5" });
panel.Controls.Add(dropDown);