WinForm多选下拉框改造(带全选和取消)
我之前看过几个大神写的WinForm的多选下拉框,但是都不太满足我的业务需求,后来我改写了一位大神写的控件,这个控件原来只能显示已选的个数,现在我改成了可以显示已选选择项的所有值,现在给大家分享一下,这个自定义多选下拉框控件带全选和取消选择功能,勾选选项之后,会将勾选的值以逗号的方式自动隔开,并显示在文本框中,满足大部分的业务场景。
1. 效果预览
2. 源代码下载
3. 关键代码解释
首选先要新建一个用户控件的项目,之后就开始在后台用代码中构建一个多选下拉框的用户自定义控件,这个控件主要由Panel,Label,CheckedListBox,TextBox几种基础控件组成,实现的原理很简单,就是用已有的控件相互的组合,在几个基础的控件里实现组合控件的业务逻辑。
实现的代码分为布局,事件,属性等几部分组成,我在这里重点描述组合事件,因为事件是关键的功能实现。
4. 暴露的公开属性
**// 显示的设置值的 TextBox 控件
private TextBox tbSelectedValue;
// 下拉箭头
private ButtonS btnSelect;
// 复选框列表项,主要的实现的关键基础控件
public CheckedListBox checkListBox;
// 全选按钮
private Label lbSelectAll;
// 取消按钮
private Label lbSelectNo;
/// <summary>
/// 获取选择项文本
/// </summary>
public string CheckedText
{
get
{
return tbSelectedValue.Text;
}
set
{
tbSelectedValue.Text = value;
}
}
/// <summary>
/// 设置数据源
/// </summary>
public object DataSource
{
set
{
this.checkListBox.DataSource = value;
}
get
{
return checkListBox.DataSource;
}
}
/// <summary>
/// 设置值
/// </summary>
public string ValueMember
{
set
{
checkListBox.ValueMember = value;
}
}
/// <summary>
/// 设置显示名称
/// </summary>
public string DisplayMember
{
set
{
checkListBox.DisplayMember = value;
}
}
/// <summary>
/// 添加项
/// </summary>
public int AddItems(object value)
{
checkListBox.Items.Add(value);
return checkListBox.Items.Count;
}
/// <summary>
/// 选项集合
/// </summary>
public CheckedListBox.ObjectCollection Items
{
get
{
return checkListBox.Items;
}
}
/// <summary>
/// 获取选中项的文本
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public string GetItemText(object item)
{
return checkListBox.GetItemText(item);
}**
5. 核心事件
其中比较重要的是单击下拉框的时候,在单击事件中要先移除复选框丢失焦点事件和复选框单击事件,因为下拉列表在单击的时候要加载已经选中的选项并设置其选中状态,所以此时不能再触发其他的选中事件,否则会让单击事件产生连锁反应。再加载完已选项后,再将这两个事件加载上。其次是在焦点丢失事件中,才开始给已选项的值字符串赋值,因为此时赋值,不会影响其他的事件。
/// <summary>
/// 单击下拉框
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void btnSelect_Click(object sender, EventArgs e)
{
if (this.frmCheckList.Visible == false)
{
Rectangle rec = this.RectangleToScreen(this.ClientRectangle);
this.frmCheckList.Location = new Point(rec.X, rec.Y + this.pnlBack.Height);
this.frmCheckList.Show();
this.frmCheckList.BringToFront();
ReloationGrip();
if (tbSelectedValue.Text != "")
{
checkListBox.LostFocus -= new EventHandler(checkListBox_LostFocus);
checkListBox.ItemCheck -= new ItemCheckEventHandler(checkListBox_ItemCheck);
foreach (string str in tbSelectedValue.Text.Split(','))
{
for (int i = 0; i < checkListBox.Items.Count; i++)
{
DataRowView drvTemp = (DataRowView)this.checkListBox.Items[i];
if (drvTemp.Row.ItemArray[0].ToString() == str)
{
checkListBox.SetItemChecked(i, true);
}
}
}
checkListBox.LostFocus += new EventHandler(checkListBox_LostFocus);
checkListBox.ItemCheck += new ItemCheckEventHandler(checkListBox_ItemCheck);
}
}
else
this.frmCheckList.Hide();
}
/// <summary>
/// 全选事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lbSelectAll_Click(object sender, EventArgs e)
{
StringBuilder sbValue = new StringBuilder();
tbSelectedValue.Text = "";
for (int i = 0; i < checkListBox.Items.Count; i++)
{
checkListBox.SetItemChecked(i, true);
DataRowView drvTemp = (DataRowView)this.checkListBox.Items[i];
sbValue.Append(drvTemp.Row.ItemArray[0].ToString() + ",");
}
tbSelectedValue.Text = sbValue.ToString();
}
/// <summary>
/// 取消全选事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lbSelectNo_Click(object sender, EventArgs e)
{
for (int i = 0; i < checkListBox.Items.Count; i++)
{
checkListBox.SetItemChecked(i, false);
}
tbSelectedValue.Text = "";
}
/// <summary>
/// 焦点丢失事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void checkListBox_LostFocus(object sender, EventArgs e)
{
//如果鼠标位置在下拉框按钮的以外地方,则隐藏下拉框
if (!this.btnSelect.RectangleToScreen(this.btnSelect.ClientRectangle).Contains(Cursor.Position))
{
frmCheckList.Hide();
CheckedText = tbSelectedValue.Text;
}
}
/// <summary>
/// 单击事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void checkListBox_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (ItemClick != null)
{
ItemClick(sender, e);
}
DataRowView drvTemp = (DataRowView)this.checkListBox.Items[e.Index];
drvTemp[2] = "True";
//获取选中的值
if (this.checkListBox.CheckedItems.Contains(this.checkListBox.Items[e.Index]))
{
if (e.NewValue != CheckState.Checked)
{
tbSelectedValue.Text = tbSelectedValue.Text.Replace(drvTemp.Row.ItemArray[0].ToString() + ",", "");
}
}
else
{
if (e.NewValue == CheckState.Checked)
{
tbSelectedValue.Text += drvTemp.Row.ItemArray[0].ToString() + ",";
}
}
}
6. 使用方法
只要在控件的Load的事件中加载要使用的选项就OK了,这里要注意,选项的数据源是个DataTable类型。这是原作者已经设计好的,我没有再进行改写。
private void multiSelect1_Load(object sender, EventArgs e)
{
//绑定数据源
DataTable dt = new DataTable();
DataColumn dc1 = new DataColumn("Name", typeof(System.String));
dt.Columns.Add(dc1);
DataColumn dc2 = new DataColumn("Index", typeof(System.String));
dt.Columns.Add(dc2);
DataColumn dc3 = new DataColumn("Judge", typeof(System.String));
dt.Columns.Add(dc3);
string[] names = new string[5] {
"小明","小红","蛋蛋","宝宝","健健"
};
foreach (string name in names)
{
DataRow dr = dt.NewRow();
dr[0] = name;
dr[1] = name;
dr[2] = "False";
dt.Rows.Add(dr);
}
multiSelect1.DataSource = dt;
multiSelect1.DisplayMember = "Name";
multiSelect1.ValueMember = "Index";
}