• 自定义 MultiColumnComboBox[转]


      1 // taken from a control written by Nishant Sivakumar.
      2 // http://www.codeproject.com/cs/combobox/DotNetMultiColumnComboBox.asp
      3 // http://www.51aspx.com/CodeFile/FengfanSell/Market/MultiColumnComboBox.cs.html
      4 // Bugfixes or Suggestions can be sent to dcaillouet@littlerock.org
      5 
      6 
      7 using System;
      8 using System.Windows.Forms;
      9 using System.Collections;
     10 using System.Collections.ObjectModel;
     11 using System.ComponentModel;
     12 using System.Drawing;
     13 using System.Globalization;
     14 
     15 namespace WindowsFormsApplication1
     16 {
     17     public class MultiColumnComboBox : ComboBox
     18     {
     19         private bool _AutoComplete;
     20         private bool _AutoDropdown;
     21         private Color _BackColorEven = Color.White;
     22         private Color _BackColorOdd = Color.White;
     23         private string _ColumnNameString = "";
     24         private int _ColumnWidthDefault = 75;
     25         private string _ColumnWidthString = "";
     26         private int _LinkedColumnIndex;
     27         private TextBox _LinkedTextBox;
     28         private int _TotalWidth = 0;
     29         private int _ValueMemberColumnIndex = 0;
     30 
     31         private Collection<string> _ColumnNames = new Collection<string>();
     32         private Collection<int> _ColumnWidths = new Collection<int>();
     33 
     34         public MultiColumnComboBox()
     35         {
     36             DrawMode = DrawMode.OwnerDrawVariable;
     37 
     38             // If all of your boxes will be RightToLeft, uncomment 
     39             // the following line to make RTL the default.
     40             //RightToLeft = RightToLeft.Yes;
     41 
     42             // Remove the Context Menu to disable pasting 
     43             ContextMenu = new ContextMenu();
     44         }
     45 
     46         public event System.EventHandler OpenSearchForm;
     47 
     48         public bool AutoComplete
     49         {
     50             get
     51             {
     52                 return _AutoComplete;
     53             }
     54             set
     55             {
     56                 _AutoComplete = value;
     57             }
     58         }
     59 
     60         public bool AutoDropdown
     61         {
     62             get
     63             {
     64                 return _AutoDropdown;
     65             }
     66             set
     67             {
     68                 _AutoDropdown = value;
     69             }
     70         }
     71 
     72         public Color BackColorEven
     73         {
     74             get
     75             {
     76                 return _BackColorEven;
     77             }
     78             set
     79             {
     80                 _BackColorEven = value;
     81             }
     82         }
     83 
     84         public Color BackColorOdd
     85         {
     86             get
     87             {
     88                 return _BackColorOdd;
     89             }
     90             set
     91             {
     92                 _BackColorOdd = value;
     93             }
     94         }
     95 
     96         public Collection<string> ColumnNameCollection
     97         {
     98             get
     99             {
    100                 return _ColumnNames;
    101             }
    102         }
    103 
    104         public string ColumnNames
    105         {
    106             get
    107             {
    108                 return _ColumnNameString;
    109             }
    110 
    111             set
    112             {
    113                 // If the column string is blank, leave it blank.
    114                 // The default width will be used for all columns.
    115                 if (!Convert.ToBoolean(value.Trim().Length))
    116                 {
    117                     _ColumnNameString = "";
    118                 }
    119                 else if (value != null)
    120                 {
    121                     char[] delimiterChars = { ',', ';', ':' };
    122                     string[] columnNames = value.Split(delimiterChars);
    123 
    124                     if (!DesignMode)
    125                     {
    126                         _ColumnNames.Clear();
    127                     }
    128 
    129                     // After splitting the string into an array, iterate
    130                     // through the strings and check that they're all valid.
    131                     foreach (string s in columnNames)
    132                     {
    133                         // Does it have length?
    134                         if (Convert.ToBoolean(s.Trim().Length))
    135                         {
    136                             if (!DesignMode)
    137                             {
    138                                 _ColumnNames.Add(s.Trim());
    139                             }
    140                         }
    141                         else // The value is blank
    142                         {
    143                             throw new NotSupportedException("Column names can not be blank.");
    144                         }
    145                     }
    146                     _ColumnNameString = value;
    147                 }
    148             }
    149         }
    150 
    151         public Collection<int> ColumnWidthCollection
    152         {
    153             get
    154             {
    155                 return _ColumnWidths;
    156             }
    157         }
    158 
    159         public int ColumnWidthDefault
    160         {
    161             get
    162             {
    163                 return _ColumnWidthDefault;
    164             }
    165             set
    166             {
    167                 _ColumnWidthDefault = value;
    168             }
    169         }
    170 
    171         public string ColumnWidths
    172         {
    173             get
    174             {
    175                 return _ColumnWidthString;
    176             }
    177 
    178             set
    179             {
    180                 // If the column string is blank, leave it blank.
    181                 // The default width will be used for all columns.
    182                 if (!Convert.ToBoolean(value.Trim().Length))
    183                 {
    184                     _ColumnWidthString = "";
    185                 }
    186                 else if (value != null)
    187                 {
    188                     char[] delimiterChars = { ',', ';', ':' };
    189                     string[] columnWidths = value.Split(delimiterChars);
    190                     string invalidValue = "";
    191                     int invalidIndex = -1;
    192                     int idx = 1;
    193                     int intValue;
    194 
    195                     // After splitting the string into an array, iterate
    196                     // through the strings and check that they're all integers
    197                     // or blanks
    198                     foreach (string s in columnWidths)
    199                     {
    200                         // If it has length, test if it's an integer
    201                         if (Convert.ToBoolean(s.Trim().Length))
    202                         {
    203                             // It's not an integer. Flag the offending value.
    204                             if (!int.TryParse(s, out intValue))
    205                             {
    206                                 invalidIndex = idx;
    207                                 invalidValue = s;
    208                             }
    209                             else // The value was okay. Increment the item index.
    210                             {
    211                                 idx++;
    212                             }
    213                         }
    214                         else // The value is a space. Use the default width.
    215                         {
    216                             idx++;
    217                         }
    218                     }
    219 
    220                     // If an invalid value was found, raise an exception.
    221                     if (invalidIndex > -1)
    222                     {
    223                         string errMsg;
    224 
    225                         errMsg = "Invalid column width '" + invalidValue + "' located at column " + invalidIndex.ToString();
    226                         throw new ArgumentOutOfRangeException(errMsg);
    227                     }
    228                     else // The string is fine
    229                     {
    230                         _ColumnWidthString = value;
    231 
    232                         // Only set the values of the collections at runtime.
    233                         // Setting them at design time doesn't accomplish 
    234                         // anything and causes errors since the collections 
    235                         // don't exist at design time.
    236                         if (!DesignMode)
    237                         {
    238                             _ColumnWidths.Clear();
    239                             foreach (string s in columnWidths)
    240                             {
    241                                 // Initialize a column width to an integer
    242                                 if (Convert.ToBoolean(s.Trim().Length))
    243                                 {
    244                                     _ColumnWidths.Add(Convert.ToInt32(s));
    245                                 }
    246                                 else // Initialize the column to the default
    247                                 {
    248                                     _ColumnWidths.Add(_ColumnWidthDefault);
    249                                 }
    250                             }
    251 
    252                             // If the column is bound to data, set the column widths
    253                             // for any columns that aren't explicitly set by the 
    254                             // string value entered by the programmer
    255                             if (DataManager != null)
    256                             {
    257                                 InitializeColumns();
    258                             }
    259                         }
    260                     }
    261                 }
    262             }
    263         }
    264 
    265         public new DrawMode DrawMode
    266         {
    267             get
    268             {
    269                 return base.DrawMode;
    270             }
    271             set
    272             {
    273                 if (value != DrawMode.OwnerDrawVariable)
    274                 {
    275                     throw new NotSupportedException("Needs to be DrawMode.OwnerDrawVariable");
    276                 }
    277                 base.DrawMode = value;
    278             }
    279         }
    280 
    281         public new ComboBoxStyle DropDownStyle
    282         {
    283             get
    284             {
    285                 return base.DropDownStyle;
    286             }
    287             set
    288             {
    289                 if (value != ComboBoxStyle.DropDown)
    290                 {
    291                     throw new NotSupportedException("ComboBoxStyle.DropDown is the only supported style");
    292                 }
    293                 base.DropDownStyle = value;
    294             }
    295         }
    296 
    297         public int LinkedColumnIndex
    298         {
    299             get
    300             {
    301                 return _LinkedColumnIndex;
    302             }
    303             set
    304             {
    305                 if (value < 0)
    306                 {
    307                     throw new ArgumentOutOfRangeException("A column index can not be negative");
    308                 }
    309                 _LinkedColumnIndex = value;
    310             }
    311         }
    312 
    313         public TextBox LinkedTextBox
    314         {
    315             get
    316             {
    317                 return _LinkedTextBox;
    318             }
    319             set
    320             {
    321                 _LinkedTextBox = value;
    322 
    323                 if (_LinkedTextBox != null)
    324                 {
    325                     // Set any default properties of the Linked Textbox here
    326                     _LinkedTextBox.ReadOnly = true;
    327                     _LinkedTextBox.TabStop = false;
    328                 }
    329             }
    330         }
    331 
    332         public int TotalWidth
    333         {
    334             get
    335             {
    336                 return _TotalWidth;
    337             }
    338         }
    339 
    340         protected override void OnDataSourceChanged(EventArgs e)
    341         {
    342             base.OnDataSourceChanged(e);
    343 
    344             InitializeColumns();
    345         }
    346 
    347         protected override void OnDrawItem(DrawItemEventArgs e)
    348         {
    349             base.OnDrawItem(e);
    350 
    351             if (DesignMode)
    352                 return;
    353 
    354             e.DrawBackground();
    355 
    356             Rectangle boundsRect = e.Bounds;
    357             int lastRight = 0;
    358 
    359             Color brushForeColor;
    360             if ((e.State & DrawItemState.Selected) == 0)
    361             {
    362                 // Item is not selected. Use BackColorOdd & BackColorEven
    363                 Color backColor;
    364                 backColor = Convert.ToBoolean(e.Index % 2) ? _BackColorOdd : _BackColorEven;
    365                 using (SolidBrush brushBackColor = new SolidBrush(backColor))
    366                 {
    367                     e.Graphics.FillRectangle(brushBackColor, e.Bounds);
    368                 }
    369                 brushForeColor = Color.Black;
    370             }
    371             else
    372             {
    373                 // Item is selected. Use ForeColor = White
    374                 brushForeColor = Color.White;
    375             }
    376 
    377             using (Pen linePen = new Pen(SystemColors.GrayText))
    378             {
    379                 using (SolidBrush brush = new SolidBrush(brushForeColor))
    380                 {
    381                     if (!Convert.ToBoolean(_ColumnNames.Count))
    382                     {
    383                         e.Graphics.DrawString(Convert.ToString(Items[e.Index]), Font, brush, boundsRect);
    384                     }
    385                     else
    386                     {
    387                         // If the ComboBox is displaying a RightToLeft language, draw it this way.
    388                         if (RightToLeft.Equals(RightToLeft.Yes))
    389                         {
    390                             // Define a StringFormat object to make the string display RTL.
    391                             StringFormat rtl = new StringFormat();
    392                             rtl.Alignment = StringAlignment.Near;
    393                             rtl.FormatFlags = StringFormatFlags.DirectionRightToLeft;
    394 
    395                             // Draw the strings in reverse order from high column index to zero column index.
    396                             for (int colIndex = _ColumnNames.Count - 1; colIndex >= 0; colIndex--)
    397                             {
    398                                 if (Convert.ToBoolean(_ColumnWidths[colIndex]))
    399                                 {
    400                                     string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], _ColumnNames[colIndex]));
    401 
    402                                     boundsRect.X = lastRight;
    403                                     boundsRect.Width = (int)_ColumnWidths[colIndex];
    404                                     lastRight = boundsRect.Right;
    405 
    406                                     // Draw the string with the RTL object.
    407                                     e.Graphics.DrawString(item, Font, brush, boundsRect, rtl);
    408 
    409                                     if (colIndex > 0)
    410                                     {
    411                                         e.Graphics.DrawLine(linePen, boundsRect.Right, boundsRect.Top, boundsRect.Right, boundsRect.Bottom);
    412                                     }
    413                                 }
    414                             }
    415                         }
    416                         // If the ComboBox is displaying a LeftToRight language, draw it this way.
    417                         else
    418                         {
    419                             // Display the strings in ascending order from zero to the highest column.
    420                             for (int colIndex = 0; colIndex < _ColumnNames.Count; colIndex++)
    421                             {
    422                                 if (Convert.ToBoolean(_ColumnWidths[colIndex]))
    423                                 {
    424                                     string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], _ColumnNames[colIndex]));
    425 
    426                                     boundsRect.X = lastRight;
    427                                     boundsRect.Width = (int)_ColumnWidths[colIndex];
    428                                     lastRight = boundsRect.Right;
    429                                     e.Graphics.DrawString(item, Font, brush, boundsRect);
    430 
    431                                     if (colIndex < _ColumnNames.Count - 1)
    432                                     {
    433                                         e.Graphics.DrawLine(linePen, boundsRect.Right, boundsRect.Top, boundsRect.Right, boundsRect.Bottom);
    434                                     }
    435                                 }
    436                             }
    437                         }
    438                     }
    439                 }
    440             }
    441 
    442             e.DrawFocusRectangle();
    443         }
    444 
    445         protected override void OnDropDown(EventArgs e)
    446         {
    447             base.OnDropDown(e);
    448 
    449             if (_TotalWidth > 0)
    450             {
    451                 if (Items.Count > MaxDropDownItems)
    452                 {
    453                     // The vertical scrollbar is present. Add its width to the total.
    454                     // If you don't then RightToLeft languages will have a few characters obscured.
    455                     this.DropDownWidth = _TotalWidth + SystemInformation.VerticalScrollBarWidth;
    456                 }
    457                 else
    458                 {
    459                     this.DropDownWidth = _TotalWidth;
    460                 }
    461             }
    462         }
    463 
    464         protected override void OnKeyDown(KeyEventArgs e)
    465         {
    466             // Use the Delete or Escape Key to blank out the ComboBox and
    467             // allow the user to type in a new value
    468             if ((e.KeyCode == Keys.Delete) ||
    469                 (e.KeyCode == Keys.Escape))
    470             {
    471                 SelectedIndex = -1;
    472                 Text = "";
    473                 if (_LinkedTextBox != null)
    474                 {
    475                     _LinkedTextBox.Text = "";
    476                 }
    477             }
    478             else if (e.KeyCode == Keys.F3)
    479             {
    480                 // Fire the OpenSearchForm Event
    481                 if (OpenSearchForm != null)
    482                 {
    483                     OpenSearchForm(this, System.EventArgs.Empty);
    484                 }
    485             }
    486         }
    487 
    488         // Some of the code for OnKeyPress was derived from some VB.NET code  
    489         // posted by Laurent Muller as a suggested improvement for another control.
    490         // http://www.codeproject.com/vb/net/autocomplete_combobox.asp?df=100&forumid=3716&select=579095#xx579095xx
    491         protected override void OnKeyPress(KeyPressEventArgs e)
    492         {
    493             int idx = -1;
    494             string toFind;
    495 
    496             DroppedDown = _AutoDropdown;
    497             if (!Char.IsControl(e.KeyChar))
    498             {
    499                 if (_AutoComplete)
    500                 {
    501                     toFind = Text.Substring(0, SelectionStart) + e.KeyChar;
    502                     idx = FindStringExact(toFind);
    503 
    504                     if (idx == -1)
    505                     {
    506                         // An exact match for the whole string was not found
    507                         // Find a substring instead.
    508                         idx = FindString(toFind);
    509                     }
    510                     else
    511                     {
    512                         // An exact match was found. Close the dropdown.
    513                         DroppedDown = false;
    514                     }
    515 
    516                     if (idx != -1) // The substring was found.
    517                     {
    518                         SelectedIndex = idx;
    519                         SelectionStart = toFind.Length;
    520                         SelectionLength = Text.Length - SelectionStart;
    521                     }
    522                     else // The last keystroke did not create a valid substring.
    523                     {
    524                         // If the substring is not found, cancel the keypress
    525                         e.KeyChar = (char)0;
    526                     }
    527                 }
    528                 else // AutoComplete = false. Treat it like a DropDownList by finding the
    529                 // KeyChar that was struck starting from the current index
    530                 {
    531                     idx = FindString(e.KeyChar.ToString(), SelectedIndex);
    532 
    533                     if (idx != -1)
    534                     {
    535                         SelectedIndex = idx;
    536                     }
    537                 }
    538             }
    539 
    540             // Do no allow the user to backspace over characters. Treat it like
    541             // a left arrow instead. The user must not be allowed to change the 
    542             // value in the ComboBox. 
    543             if ((e.KeyChar == (char)(Keys.Back)) &&  // A Backspace Key is hit
    544                 (_AutoComplete) &&                   // AutoComplete = true
    545                 (Convert.ToBoolean(SelectionStart))) // And the SelectionStart is positive
    546             {
    547                 // Find a substring that is one character less the the current selection.
    548                 // This mimicks moving back one space with an arrow key. This substring should
    549                 // always exist since we don't allow invalid selections to be typed. If you're
    550                 // on the 3rd character of a valid code, then the first two characters have to 
    551                 // be valid. Moving back to them and finding the 1st occurrence should never fail.
    552                 toFind = Text.Substring(0, SelectionStart - 1);
    553                 idx = FindString(toFind);
    554 
    555                 if (idx != -1)
    556                 {
    557                     SelectedIndex = idx;
    558                     SelectionStart = toFind.Length;
    559                     SelectionLength = Text.Length - SelectionStart;
    560                 }
    561             }
    562 
    563             // e.Handled is always true. We handle every keystroke programatically.
    564             e.Handled = true;
    565         }
    566 
    567         protected override void OnSelectedValueChanged(EventArgs e)
    568         {
    569             base.OnSelectedValueChanged(e); //Added after version 1.3 on 01/31/2008
    570 
    571             if (_LinkedTextBox != null)
    572             {
    573                 if (_LinkedColumnIndex < _ColumnNames.Count)
    574                 {
    575                     _LinkedTextBox.Text = Convert.ToString(FilterItemOnProperty(SelectedItem, _ColumnNames[_LinkedColumnIndex]));
    576                 }
    577             }
    578         }
    579 
    580         protected override void OnValueMemberChanged(EventArgs e)
    581         {
    582             base.OnValueMemberChanged(e);
    583 
    584             InitializeValueMemberColumn();
    585         }
    586 
    587         private void InitializeColumns()
    588         {
    589             if (!Convert.ToBoolean(_ColumnNameString.Length))
    590             {
    591                 PropertyDescriptorCollection propertyDescriptorCollection = DataManager.GetItemProperties();
    592 
    593                 _TotalWidth = 0;
    594                 _ColumnNames.Clear();
    595 
    596                 for (int colIndex = 0; colIndex < propertyDescriptorCollection.Count; colIndex++)
    597                 {
    598                     _ColumnNames.Add(propertyDescriptorCollection[colIndex].Name);
    599 
    600                     // If the index is greater than the collection of explicitly
    601                     // set column widths, set any additional columns to the default
    602                     if (colIndex >= _ColumnWidths.Count)
    603                     {
    604                         _ColumnWidths.Add(_ColumnWidthDefault);
    605                     }
    606                     _TotalWidth += _ColumnWidths[colIndex];
    607                 }
    608             }
    609             else
    610             {
    611                 _TotalWidth = 0;
    612 
    613                 for (int colIndex = 0; colIndex < _ColumnNames.Count; colIndex++)
    614                 {
    615                     // If the index is greater than the collection of explicitly
    616                     // set column widths, set any additional columns to the default
    617                     if (colIndex >= _ColumnWidths.Count)
    618                     {
    619                         _ColumnWidths.Add(_ColumnWidthDefault);
    620                     }
    621                     _TotalWidth += _ColumnWidths[colIndex];
    622                 }
    623 
    624             }
    625 
    626             // Check to see if the programmer is trying to display a column
    627             // in the linked textbox that is greater than the columns in the 
    628             // ComboBox. I handle this error by resetting it to zero.
    629             if (_LinkedColumnIndex >= _ColumnNames.Count)
    630             {
    631                 _LinkedColumnIndex = 0; // Or replace this with an OutOfBounds Exception
    632             }
    633         }
    634 
    635         private void InitializeValueMemberColumn()
    636         {
    637             int colIndex = 0;
    638             foreach (String columnName in _ColumnNames)
    639             {
    640                 if (String.Compare(columnName, ValueMember, true, CultureInfo.CurrentUICulture) == 0)
    641                 {
    642                     _ValueMemberColumnIndex = colIndex;
    643                     break;
    644                 }
    645                 colIndex++;
    646             }
    647         }
    648     }
    649 }
  • 相关阅读:
    开课吧-孤尽公开课视频内容整理笔记
    业务系统数据库设计经验总结(七)-强制使用选定索引
    业务系统数据库设计经验总结(六)-MySQL中ORDER BY LIMIT分页数据性能问题
    业务系统数据库设计经验总结(五)-MySQL中ORDER BY LIMIT分页数据重复问题
    mongoTemplate聚合统计字段类型为字符串的数据,根据时间日期月份进行统计,日期也为字符串
    预览在线的pdf
    react页面缓存 使用本地存储
    react页面缓存插件 react-router-cache-router
    README.md的基本语法使用
    eclipse tomcat的一些错误
  • 原文地址:https://www.cnblogs.com/z5337/p/3678880.html
Copyright © 2020-2023  润新知