combobox控件实现多列显示

      该程序主要参考codeProject上的一个程序,链接已失去,不过要想其致敬!

    

      默认的combobox是不提供多列显示的,所以这里要用绘制的方法显示该功能,主要是重写combobox。其中combobox有个属性DrawMode,需将其设为DrawMode.OwnerDrawVariable,原因如下:从MSDN摘录.

Normal 控件中的所有元素都由操作系统绘制,并且元素大小都相等。 
OwnerDrawFixed 控件中的所有元素都是手动绘制的,并且元素大小都相等。 
OwnerDrawVariable 控件中的所有元素都由手动绘制,元素大小可能不相等。 

      具体步骤如下:实例以datatable为数据源,数据源也可以是arraylist或通过add()方法添加

         int columnPadding = 5;
        private float[] columnWidths = new float[0];  //项宽度
        private String[] columnNames = new String[0]; //项名称
        private int valueMemberColumnIndex = 0;       //valueMember属性列所在的索引

   /// <summary>
        
/// 绑定数据源或更改数据源时发生
        
/// </summary>
        
/// <param name="e"></param>

        protected override void OnDataSourceChanged(EventArgs e)
        
{
            
base.OnDataSourceChanged(e);

            InitializeColumns();
        }



        
/// <summary>
        
/// 设置ValueMember属性发生
        
/// </summary>
        
/// <param name="e"></param>

        protected override void OnValueMemberChanged(EventArgs e)
        
{
            
base.OnValueMemberChanged(e);

            InitializeValueMemberColumn();
        }



        
/// <summary>
        
/// 显示下拉框的时候触发
        
/// </summary>
        
/// <param name="e"></param>

        protected override void OnDropDown(EventArgs e)
        
{
            
base.OnDropDown(e);
            
this.DropDownWidth = (int)CalculateTotalWidth();  //计算combobox下拉框的总宽度
        }




   
/// <summary>
        
/// 初始化数据源各列的名称
        
/// </summary>

        private void InitializeColumns()
        
{
            PropertyDescriptorCollection propertyDescriptorCollection 
= DataManager.GetItemProperties();

            columnWidths 
= new float[propertyDescriptorCollection.Count];
            columnNames 
= new String[propertyDescriptorCollection.Count];

            
for (int colIndex = 0; colIndex < propertyDescriptorCollection.Count; colIndex++)
            
{
                String name 
= propertyDescriptorCollection[colIndex].Name;
                columnNames[colIndex] 
= name;
            }

        }



        
/// <summary>
        
/// 返回ValueMember在显示列中的索引位置
        
/// </summary>

        private void InitializeValueMemberColumn()
        
{
            
int colIndex = 0;
            
foreach (String columnName in columnNames)
            
{
                
if (String.Compare(columnName, ValueMember, true, CultureInfo.CurrentUICulture) == 0)
                
{
                    valueMemberColumnIndex 
= colIndex;
                    
break;
                }

                colIndex
++;
            }

        }



        
/// <summary>
        
/// 计算combobox下拉框的总宽度
        
/// </summary>
        
/// <returns></returns>

        private float CalculateTotalWidth()
        
{

            columnPadding 
= 5;
            
float totWidth = 0;
            
foreach (int width in columnWidths)
            
{
                totWidth 
+= (width + columnPadding);
            }


            
//总宽度加上垂直滚动条的宽度
            return totWidth + SystemInformation.VerticalScrollBarWidth;
        }

绘制字符串所使用的两个方法:

 /// <summary>
        
/// 获得各列的宽度和项的总宽度
        
/// 引发 MeasureItem 事件
        
/// </summary>
        
/// <param name="e"></param>

        protected override void OnMeasureItem(MeasureItemEventArgs e)
        
{
            
base.OnMeasureItem(e);

            
if (DesignMode)
                
return;

            
for (int colIndex = 0; colIndex < columnNames.Length; colIndex++)
            
{
                
//如果 ListControl 项是被给定了该项以及属性名称的对象的属性,则返回该项的当前值
                string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], columnNames[colIndex]));
                SizeF sizeF 
= e.Graphics.MeasureString(item, Font);  //返回显示项字符串的大小
                columnWidths[colIndex] = Math.Max(columnWidths[colIndex], sizeF.Width);
            }


            
float totWidth = CalculateTotalWidth(); //计算combobox下拉框项宽度

            e.ItemWidth 
= (int)totWidth;   //设置combobox下拉框项宽度
        }




        
/// <summary>
        
/// 绘制下拉框的内容
        
/// 引发 DrawItem 事件
        
/// </summary>
        
/// <param name="e"></param>

        protected override void OnDrawItem(DrawItemEventArgs e)
        
{
            
base.OnDrawItem(e);

            
if (DesignMode)
                
return;

            e.DrawBackground();

            Rectangle boundsRect 
= 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 colIndex = 0; colIndex < columnNames.Length; colIndex++)
                        
{
                            
string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], columnNames[colIndex]));

                            boundsRect.X 
= lastRight;  //列的左边位置
                            boundsRect.Width = (int)columnWidths[colIndex] + columnPadding; //列的宽度
                            lastRight = boundsRect.Right;

                            
if (colIndex == valueMemberColumnIndex)//如果是valueMember项
                            {
                                
using (Font boldFont = new Font(Font, FontStyle.Bold))
                                
{

                                    
//绘制项的内容
                                    e.Graphics.DrawString(item, boldFont, brush, boundsRect);
                                }

                            }

                            
else
                            
{
                                
//绘制项的内容
                                e.Graphics.DrawString(item, Font, brush, boundsRect);
                            }



                            
//绘制各项间的竖线
                            if (colIndex < columnNames.Length - 1)
                            
{
                                e.Graphics.DrawLine(linePen, boundsRect.Right, boundsRect.Top, boundsRect.Right, boundsRect.Bottom);
                            }

                        }

                    }

                }

            }


            e.DrawFocusRectangle();
        }

 界面层绑定数据源:

            DataTable dataTable = new DataTable("Employees");

            dataTable.Columns.Add(
"Employee ID"typeof(String));
            dataTable.Columns.Add(
"Name"typeof(String));
            dataTable.Columns.Add(
"Country"typeof(String));
            dataTable.Rows.Add(
new String[] "1""James""USA" });
            dataTable.Rows.Add(
new String[] "2""Mary""UK" });
            dataTable.Rows.Add(
new String[] "3""Jack""Japan" });

      有需要源码的朋友同样可以到我的群中下载.

原文地址:https://www.cnblogs.com/gossip/p/1371984.html