2013年(56)
分类: C#/.net
2013-10-09 14:50:17
高考结束了,马上又将会有这么一群孩子,迫不及待的扔下书包,去聚餐,通宵上网,旅行,KTV,闲逛,狂欢……认为自己终于解放了……殊不知,你们离开的,就是天堂。
-- 致 即将步入社会的孩纸们
缘由
最近在维护一个winform项目,公司购买的是DevExpress控件 (请问怎么联系DevExpress工作人员? 我想询问下,广告费是怎么给的。:p),经过公司大牛们对DevExpress控件疯狂的重写、封装、加密、混淆...等一系列的操作,制作了一套 安全+实用 、基于DevExpress控件又高于DevExpress控件的模板。此时,大家也许觉得我夸张了。但是哥很淡定的告诉大家:不信拉倒!
一系列绚丽的控件中,目前最让我久久不能忘记吃早餐的就是ComboBoxEdit的显示多列的功能。所以我就想,能不能用普通的ComboBox控件实现这样的功能,带着这样的问题询问了没有被公司网络限制的度娘,结果度娘告诉我需要用一个TextBox结合一个ListView或者GridView来实现这样的功能。我嘞个去~ 这不是和Web里面DIV的显示和隐藏一样了么。 搞得跟个二五八萬似的! 深叹一口气,脑子一转想起了上篇《公用章水印工具》中用到的GDI+,于是有了下文:
实施:新建组件类
首先,新建一个winform窗体项目,新建一个组件类,并让其继承ComboBox控件类.
public partial class MyComboBox : ComboBox
然后,就是需要做的就是:重写涉及到下拉列表显示的事件了。重写之前需要注意到一点是:将ComboBox控件的DrawMode 设置为DrawMode.OwnerDrawVariable(手动绘制元素)
无废话,直接贴出核心代码:
///
/// 初始化数据源各列的名称 ///
private void InitializeColumns() { PropertyDescriptorCollection
propertyDescriptorCollection = DataManager.GetItemProperties(); columnWidths =
new float[propertyDescriptorCollection.Count]; columnNames = new
string[propertyDescriptorCollection.Count]; for (int i = 0; i <
propertyDescriptorCollection.Count; i++) { string name =
propertyDescriptorCollection[i].Name; columnNames[i] = name; } } ///
/// 显示下拉框的时候出发 ///
///
protected override void OnDropDown(EventArgs e) { base.OnDropDown(e); this.DropDownWidth = (int)CalculateTotalWidth();//计算下拉框的总宽度
}private float CalculateTotalWidth() { columnPadding = 5; float totalWidth = 0; foreach (int width in columnWidths) { totalWidth += (width + columnPadding); } //总宽度加上垂直滚动条的宽度
return totalWidth + SystemInformation.VerticalScrollBarWidth; } ///
/// 获取各列的宽度和项的总宽度 ///
///
protected override void OnMeasureItem(MeasureItemEventArgs e) { base.OnMeasureItem(e); if (DesignMode) { return; } InitializeColumns(); for (int i = 0; i < columnNames.Length; i++) { string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], columnNames[i])); SizeF sizeF = e.Graphics.MeasureString(item, Font);//返回显示项字符串的大小
columnWidths[i] = Math.Max(columnWidths[i], sizeF.Width); } float totalWidth = CalculateTotalWidth();//计算combobox下拉框项的宽度
e.ItemWidth = (int)totalWidth;//设置下拉框项的宽度
} ///
/// 绘制下拉框的内容 ///
///
protected override void OnDrawItem(DrawItemEventArgs e) { base.OnDrawItem(e); if (DesignMode) { return; } Rectangle boundsRect = e.Bounds;//获取绘制项边界的矩形 //e.DrawBackground();
e.Graphics.FillRectangle(Brushes.Bisque, e.Bounds); if ((e.State & DrawItemState.Focus) == 0) { //设置鼠标悬浮ComboBox的item的背景色
e.Graphics.FillRectangle(Brushes.White, e.Bounds); } int lastRight = 0; using (Pen linePen = new Pen(SystemColors.GrayText)) { using (SolidBrush brush = new SolidBrush(ForeColor)) { if (columnNames.Length == 0) {e.Graphics.DrawString(Convert.ToString(Items[e.Index]), Font, brush, boundsRect); } else {//循环各列
for (int i = 0; i < columnNames.Length; i++){ string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], columnNames[i])); boundsRect.X = lastRight;//列的左边位置
boundsRect.Width = (int)columnWidths[i] + columnPadding;//列的宽度
lastRight = boundsRect.Right; //绘制项的内容
e.Graphics.DrawString(item, Font, brush, boundsRect);//绘制各项间的竖线
if (i < columnNames.Length - 1) { e.Graphics.DrawLine(linePen, boundsRect.Right, boundsRect.Top, boundsRect.Right, boundsRect.Bottom); }} } } } e.DrawFocusRectangle();}
上述代码没有什么亮点,稍微了解点GDI+的都能看懂,而且有很丰富的注释。就不一一解释了。